+ Start a Discussion

Help displaying page messages on wizard VF pages

I have attempted to recreate the functionality of the opportunity/opportunity line item model with a pair of custom objects salesorder/sales order product.  Everything is functioning the way I want...almost.


I use a wizard like set-up to replicate the functionality of adding a product to an opportunity with my custom objects. 



I do not set redirect to true in my controller because I want to have access to the list of selected products from the edit page (this is the "second" page in my wizard). 


The problem is that I have some validation rules that trigger based on user input on this second page and if redirect is not set to true when leaving the first page I don't get any page messages on the second page.  When the validation rule throws an exception the page just redirects to the detail page of the sales order object like it saved the line items, but it hasn't saved any line items because there are errors.


This same problem exists if you use the wizard example from the cookbook.


Partial controller code:


This method is called when the user clicks the "save" button on the first page:



public PageReference processSelected(){ System.debug('test ID=' + salesOrderId); /*We create a new list of PriceBookEntrys that will be populated only with PriceBookEntrys if they are selected*/ selectedProducts = new List<PriceBookEntry>(); if (lineItems == null) lineItems = new List<SalesOrderLineItem__c>(); /*We will cycle through our list of wPBEs and will check to see if the selected property is set to true, if it is we add the PriceBookEntry to the selectedPBEs list. */ for(wPBE wProduct : productList){ if(wProduct.selected == true){ selectedProducts.add(wProduct.product); SalesOrderLineItem__c lineItem = new SalesOrderLineItem__c(Name=wProduct.product.ProductCode, product__c=wProduct.product.Product2ID, List_Price__c = wProduct.product.UnitPrice, Sales_Price__c = wProduct.product.UnitPrice, Sales_Order__c=salesOrder.Id); lineItems.add(lineItem); System.debug('Added lineItem' + lineItem.product__c); } // end if statment } // end for loop /* Now we have our list of selected PriceBookEntrys and can perform any type of logic we want, sending emails, updating a field on the PriceBookEntry, etc */ /*System.debug('These are the selected PriceBookEntrys...' + selectedProducts.size()); for(PriceBookEntry entry : selectedProducts){ System.debug(entry); } */ try { if(getSelectedProducts() == null || getSelectedProducts().size()== 0) throw new noProductsSelectedException('You must select at least one product to continue'); PageReference detail = page.newSOLIEdit2; return detail; }catch(noProductsSelectedException ex){ ApexPages.addMessages(ex); return null; } } // end method processSelected()



This is the method called when the user clicks the save button on the second page



public PageReference save(){ System.debug('In save()'); try{ Database.SaveResult[] sr = Database.Insert(lineItems); PageReference detail = new PageReference('/' + salesOrderId ); detail.setRedirect(true); return detail; }catch(DmlException e){ System.debug('In catch block of save()'); ApexPages.addMessages(e); //detail.setRedirect(false); //return null; } // end try-catch block PageReference detail = new PageReference('/' + salesOrderId ); detail.setRedirect(true); return detail; } // end method save()



VF page 1:



<apex:page controller="sOLIController" tabStyle="Sales_Order__c" > <apex:sectionHeader title="Sales Order {!salesOrder.Name} " subtitle="Product Selection"/> <style type="text/css"> .exceptionText { font-style:italic; font-weight:bold; color:red;} </style> <apex:messages styleClass="exceptionText"/> <apex:form > <p style="margin-left:10px"> Enter your keyword and filter criteria, then click Search to begin your search. Click More filters to use more than one filter. Search results include all records that match both your keyword <br/>and filter entries. </p><br/> <p style=" text-align:center"> <apex:commandButton value="Select" action="{!processSelected}"> <apex:param assignTo="{!salesOrderID" value="{!$CurrentPage.parameters.id}" name="soID2"/> </apex:commandButton> <apex:commandButton value="Cancel" action="{!cancel}"/> </p> <apex:pageBlock id="block1" > <apex:facet name="header"> <h2>Find Products[{!numberOfProducts}]</h2> </apex:facet> <table style="background-color:lightgrey" width="100%" > <thead> <tr> <th>by Keyword <br/> </th> </tr> </thead> <tbody> <tr> <td> <apex:inputText value="{!searchTerm}"/> </td> </tr> </tbody> <tfoot> <tr> <td><p> <apex:commandButton value="Search" action="{!doSearch}" reRender="block1"/> </p> <br/> </td> </tr> </tfoot> </table> <apex:pageBlockTable value="{!products}" var="p" id="productsTable" rows="25" first="0"> <apex:column width="10" > <apex:inputCheckbox value="{!p.selected}"/> </apex:column> <apex:column value="{!p.product.ProductCode}" width="350" > <apex:facet name="header"> &nbsp; ;nbsp <apex:commandLink value="Product Name"/> </apex:facet> </apex:column> <apex:column value="{!p.product.UnitPrice}"/> <apex:column value="{!p.product.Product2.Description}"/> <apex:column value="{!p.product.Product2.Family}"/> </apex:pageBlockTable> </apex:pageBlock> </apex:form> </apex:page>



VF page2:



<apex:page controller="sOLIController" tabStyle="Sales_Order__c" > <apex:sectionHeader title="Add Products to Sales Order {!salesOrder.Name} "/> <style type="text/css"> .exceptionText { font-style:italic; font-weight:bold; color:red;} </style> <apex:messages styleClass="exceptionText"/> <apex:form > <p style="margin-left:10px"> Add products to this sales order from <b>Standard</b> price book </p><br/> <p style=" text-align:center"> <apex:commandButton value="Save" action="{!save}" reRender="table1"/> <apex:commandButton value="Cancel" action="{!cancel}"/> </p> <apex:dataTable value="{!lineItems}" style="border:black solid 2px" cellpadding="10px" bgcolor="lightgrey" width="100%" rules="rows" var="b"> <apex:column headerValue="Product" width="250"> <b><apex:outputText value="{!b.Name}"/> </b> </apex:column> <apex:column headerValue="List Price" width="100"> <apex:outputText value="{!b.List_Price__c}"/> </apex:column> <apex:column headerValue="Special Pricing" > <apex:inputField value="{!b.Special_Pricing__c}"/> </apex:column> <apex:column headerValue="Quantity" style="font-color:red" > <apex:inputField value="{!b.Quantity__c}" required="true"/> </apex:column> <apex:column headerValue="Special Price"> <apex:inPutText value="{!b.Special_Price__c}"/> </apex:column> <apex:column > <apex:inputField value="{!b.Sales_Price__c}"/> <apex:facet name="header"> <p style="text-color:red">Sales Price </p></apex:facet> </apex:column> </apex:dataTable> </apex:form> </apex:page>


Any suggestions on how I can get my error messages to display on the second page of my wizard and prevent the save from happening if there are errors?




I would suggest adopting the following strategy:


When there are errors return null as a PageReference to remain on the same page.


The only time you need concern yourself about setRedirect is if you want to reset/restart your wizard (in which case you use true). When you redirect to a page outside your controller true is implied (and when you redirect to another page in your wizard you don't want true, save for the case cited above).





Thanks for the response Gino.


I have tried just returning null in the catch block....that does prevent the page from redirecting, but my page messages still aren't visible.  When I click the save button I can see in the debug log that the save method is executed and the message is added to the page, but the page doesn't reload/refresh to display it.  To the user (without the benefit of the debug log) it appears as if nothing happens when the save button is clicked.




Make sure you are re-rendering your messages component as well when you invoke the save action.


Also, I've always used pageMessages rather than messages (if the above fixes the problem then don't worry about it).


Other than the styling I'm not really sure what the difference is between the two (there's actually a thread where the differences are discussed but from what I recall there was no definitive conclusion).