+ Start a Discussion
cmarz_1cmarz_1 

Visualforce page with fields set programatically not updating

 

I created a custom controller as an extension to the standard Opportunity cotroller.  My visualforce page lists all of the OpportunityLineItems.  When a picklist changes it launches (actionsupport) a method in my custom controller called recalcProtex.  This method sets a number of custom fields based on the picklist selection.  The visualforce page updates the values via the rerender attruibute on my actionsupport. So the values are showing properly on the page but when I save the values are not updating in Salesforce. The OpportunityLineItems fields that my method set are equal to null (orginal value) when mySave() medthod is called.  What am I doing wrong?  The field in question is Actual_List_Price__c

 

Apex Class

 

 public class OppLineItemController {

private Opportunity opp;

public OppLineItemController(ApexPages.StandardController controller) {
this.opp = (Opportunity)controller.getRecord();
System.debug(opp.OpportunityLineItems[0].Actual_List_Price__c); // Set to null, which is correct

}

public PageReference recalcProtex( ) {
for(OpportunityLineItem oli : opp.OpportunityLineItems){
if(oli.PricebookEntry.Name == 'Protex'){
if (oli.Protex_Option__c != 'None'){
List<String> option = oli.Protex_Option__c.split(' ',-1);
System.debug(option);
// Users
oli.Users__c = option[0];
// Code Limit
oli.Code_Base_in_MB__c = option[2];
// List Price
String price= option[5].substring(1);
oli.Actual_List_Price__c = double.valueOf(price);
}
}
}
System.debug(opp.OpportunityLineItems[0].Actual_List_Price__c); // Set to proper value, e.g. not null

return null;
}

public PageReference mySave() {
System.debug(opp.OpportunityLineItems[0].Actual_List_Price__c); // Set to null again, why?

update opp.OpportunityLineItems;
PageReference oppPage = new PageReference('/' +System.currentPageReference().getParameters().get('id'));
return oppPage;
}
}

 

Visualforce Page

 

<apex:page standardController="Opportunity" extensions="OppLineItemController" tabstyle="Opportunity" >
<apex:form id="form1" >
<apex:pageBlock title="Products">
<apex:pageBlockTable value="{!Opportunity.OpportunityLineItems}" var="oli" cellpadding="4" >
<apex:column headerValue="Name" > {!oli.PricebookEntry.Name} </apex:column>
<apex:column headerValue="Option" >
<apex:inputField value="{!oli.Protex_Option__c}"> <apex:actionSupport event="onchange" action="{!recalcProtex}" rerender="ListPrice" /> </apex:inputField>
</apex:column>
<apex:column headerValue="List Price" id="ListPrice" >{!oli.Actual_List_Price__c} </apex:column>
</apex:pageBlockTable>
</apex:pageBlock>
<apex:commandButton action="{!mySave}" value="Save Products"/>
</apex:form>
</apex:page>

 

Best Answer chosen by Admin (Salesforce Developers) 
Ron HessRon Hess

do something like this :

 

 

<apex:outputPanel id="ListPriceTable" > <apex:pageBlockTable value="{!Opportunity.OpportunityLineItems}" var="oli" cellpadding="4" > <apex:column headerValue="Name" > {!oli.PricebookEntry.Name} </apex:column> <apex:column headerValue="Option" > <apex:inputField value="{!oli.Protex_Option__c}"> <apex:actionSupport event="onchange" action="{!recalcProtex}" rerender="ListPriceTable" /> </apex:inputField> </apex:column> <apex:column headerValue="List Price" id="ListPrice" >{!oli.Actual_List_Price__c} </apex:column> </apex:pageBlockTable> </apex:pageBlock> </apex:outputPanel>

 

The idea is that the output panel is outside the table , so the entire table will be refreshed, instead of the page.

 

you cannot refresh just a single column of a table, i believe this is a limitation of HTML ( in IE if i recall)

 

So, you go for the DIV outside the table  as your refresh point.

 

that avoids refreshing the entire page and re-running the page constructor.

 

 

All Answers

Ron HessRon Hess

i think what is happening is that the standard controller is called again when you redraw the page, thus overwriting the total that you calculated.

 

here is what i think is going on: 

 

page works as you designed,

but rerender on a column is not hooked up (on our side) so the entire page is re-drawn

the entire page then causes the standard controller to fetch the opportunity record again, tossing your calculated value.

 


my theory has large holes in it, but somehow you need to prove that the opp lineitems list has not been re-fetched between the time you modified it , and the time you go to save it.

 

 

 

cmarz_1cmarz_1
Ron to me this sounds like reasonable explanation.  Not sure how I would prove it, the fact that the fields are being reset back to their original state at some point between the rerender and the call to my save command seem to indicate you are correct.  I have temporarily solved the issue by calling the recalcProtex method before I update the Opportunity Line Items.  Do you think this is a bug that I should report?  If so how?
cmarz_1cmarz_1
Ron I am convinced your theory is fact.  This has gone form a minor annoyance to a huge problem.  I'm building a system where my sales reps can easily enter data and get back calculated prices to quote to the customer.  However with each change that is being made on the page all the programatically set fields are reverting to the original values.  I even tried to store the list of line items in a separate list but nothing I do stops the values from reverting to the original values each time.  Please help.
Ron HessRon Hess

do something like this :

 

 

<apex:outputPanel id="ListPriceTable" > <apex:pageBlockTable value="{!Opportunity.OpportunityLineItems}" var="oli" cellpadding="4" > <apex:column headerValue="Name" > {!oli.PricebookEntry.Name} </apex:column> <apex:column headerValue="Option" > <apex:inputField value="{!oli.Protex_Option__c}"> <apex:actionSupport event="onchange" action="{!recalcProtex}" rerender="ListPriceTable" /> </apex:inputField> </apex:column> <apex:column headerValue="List Price" id="ListPrice" >{!oli.Actual_List_Price__c} </apex:column> </apex:pageBlockTable> </apex:pageBlock> </apex:outputPanel>

 

The idea is that the output panel is outside the table , so the entire table will be refreshed, instead of the page.

 

you cannot refresh just a single column of a table, i believe this is a limitation of HTML ( in IE if i recall)

 

So, you go for the DIV outside the table  as your refresh point.

 

that avoids refreshing the entire page and re-running the page constructor.

 

 

This was selected as the best answer
cmarz_1cmarz_1
Ron, thanks so much that worked.  There should be a note about that issue somewhere in the pageBlockTable documentation so other VF nubies don't run into this issue.  For the record I was using Firefox.  Thanks again! :smileyvery-happy:
Ron HessRon Hess
Noted, thanks!