1

Visualforce is not refreshing the pageblocksection under outpanel to get the latest values from controller on click of saveedit command link

 public class NewEventController2 {

  public Id seriesId {get;set;}

  public list<Test_Event__c> feToUpdate;

  public list<Test_Event_Controller__c> fecToUpdate;

  public Test_Event_Controller__c fec {get;set;}

  public list<Test_Event__c> newfevenlist {get;set;}

   public list<Test_Event__c> finalfevenlist {get;set;}

   public Test_Event__c tempfevent = new  Test_Event__c();

   public Test_Event_Controller__c newfec {get;set;}

    public Test_Event__c fevent {get;set;}

   String recType;

  public String pListValue{get;set;}

   public Test_Event__c editEvent {get;set;} 

   Public Boolean showFields {get;set;}

   Public set<Id>fIds = new set<Id>();

   public boolean showButtons{get;set;}

   public NewEventController2(){

   seriesId = ApexPages.currentPage().getParameters().get('id');
    system.debug('....'+seriesId);
    newfec = new Test_Event_Controller__c();
    fevent = new Test_Event__c();
    showFields = false;
    showButtons = true;
   }

  public String getFundingLevelSelected() {
     return pListValue;
   } 

   public void setFundingLevelSelected(String pListValue) {
    this.pListValue= pListValue;
  }

public List<SelectOption> getPickListValue()
{
  List<SelectOption> options = new List<SelectOption>();
  Schema.DescribeFieldResult fieldResult = Test_Event__c.Funding_Level__c.getDescribe();
  List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();
  options.add(new SelectOption('', '--None--'));
  for(Schema.PicklistEntry f : ple)
  {
    if(f.getValue() != 'Organization')
    {
      options.add(new SelectOption(f.getLabel(), f.getValue()));
     }
   } 
   return options;           
 }

public String getParam(String name) {
    return ApexPages.currentPage().getParameters().get(name);   
}

 public PageReference editFundingEvents(){
    String editId= getParam('editId');
       editEvent= [Select f.Status__c, f.Series__c, f.RecordTypeId, f.Program__c, f.Number_of_years_of_the_Test_Event__c, f.Name, f.Id,f.Funding_Vehicle__c, f.Funding_Type__c, f.Funding_Level__c, f.Amount__c,f.Staff_Count__c From Test_Event__c f where f.Id= :editId];
       return null;    
}

public PageReference edit(){
       showButtons  = true;
       showFields = false;
       return null;    
}

public PageReference saveEdit() {
    try {
          Test_Event__c newfe = new Test_Event__c();
          for(Integer i=0;i < finalfevenlist.size();i++){
          if(finalfevenlist[i].Id == editEvent.Id)
          {
            newfe.Status__c = finalfevenlist[i].Status__c;
            newfe.Funding_Vehicle__c = finalfevenlist[i].Funding_Vehicle__c;
            newfe.Fiscal_Year__c = finalfevenlist[i].Fiscal_Year__c;
            newfe.Start_of_Period__c = finalfevenlist[i].Start_of_Period__c;
            newfe.End_of_Period__c = finalfevenlist[i].End_of_Period__c;
            newfe.Funding_Level__c = finalfevenlist[i].Funding_Level__c;
            newfe.Project__c = finalfevenlist[i].Project__c;
            newfe.Program__c = finalfevenlist[i].Program__c;
            newfe.Amount__c = finalfevenlist[i].Amount__c;
            newfe.Budget_Expenses__c = finalfevenlist[i].Budget_Expenses__c;
            newfe.Series__c = finalfevenlist[i].Series__c;
            newfe.Campaign__c = finalfevenlist[i].Campaign__c;
            newfe.Opportunity__c = finalfevenlist[i].Opportunity__c;
            newfe.Number_of_years_of_the_Test_Event__c = finalfevenlist[i].Number_of_years_of_the_Test_Event__c;
            newfe.RecordTypeId = finalfevenlist[i].RecordTypeId;
            newfe.Test_Event_Controller__c = finalfevenlist[i].Test_Event_Controller__c;
           }
         }
         insert newfe;
         system.debug('......newfe....'+newfe);
         feToUpdate = [Select f.Won__c, f.Status__c, f.Start_of_Period__c,f.End_of_Period__c,f.Start_Date__c, f.Staff_Count__c, f.Series__c, f.RecordTypeId, f.Project__c, f.Program__c, f.Opportunity__c,f.Opportunity__r.CloseDate, f.Opportunity__r.Amount, f.Opportunity__r.Name, f.Opportunity__r.Id, f.Number_of_years_of_the_Test_Event__c, f.Name, f.Id,f.Funding_Vehicle__c, f.Funding_Type__c, f.Funding_Level__c, f.Fiscal_Year__c, f.Fiscal_Year_Start_Date__c, f.End_Date__c, f.Campaign__c, f.Budget_Expenses__c, f.Amount__c, f.Active__c,Test_Event_Controller__c From Test_Event__c f where f.Id=:editEvent.Id];
         feToUpdate[0].Status__c = 'Cancelled';
         update feToUpdate[0];

         Double tempAmt=0;
         for(Integer i=0;i < finalfevenlist.size();i++){
          tempAmt += finalfevenlist[i].Amount__c;
         }
        system.debug('...finalfevenlist[0].Test_Event_Controller__c....'+ finalfevenlist[0].Test_Event_Controller__c);
        fecToUpdate = [Select f.Id,f.Amount__c from Test_Event_Controller__c f where f.Id =:finalfevenlist[0].Test_Event_Controller__c];
        fecToUpdate[0].Amount__c = tempAmt;
        system.debug('...fecToUpdate[0].Amount__c....'+ fecToUpdate[0].Amount__c);
        update fecToUpdate[0]; 
        system.debug('...fecToUpdate[0]...'+ fecToUpdate[0]);
        editEvent = null;
        } catch (Exception e) {
        ApexPages.addMessages(e);
    }


      return null;
}

 public PageReference cancelEdit() {
    editEvent = null;
    return null;
}  

 public PageReference Save(){
 newfevenlist = new list<Test_Event__c>();
 system.debug('.....'+fevent);
 fevent.Series__c = seriesId;
 showFields = true;
 showButtons = false;
 fec = new Test_Event_Controller__c(Amount__c = newfec.Amount__c,Number_of_Years__c =newfec.Number_of_Years__c,Fiscal_Year__c =newfec.Fiscal_Year__c,Status__c = newfec.Status__c,Grantor__c = newfec.Grantor__c,Grantee__c = newfec.Grantee__c,Funding_Vehicle__c = newfec.Funding_Vehicle__c,Funding_Level__c = pListValue,Staff_Count__c = newfec.Staff_Count__c,Budget_Expenses__c = newfec.Budget_Expenses__c,Project__c = newfec.Project__c,Program__c = newfec.Program__c);
  insert fec;
  Id rectype=[SELECT ID, name FROM RecordType WHERE SObjectType = 'Test_Event__c' and name='External'].Id;


  if(newfec.Number_of_years__c>0){
    Integer totalYears = (newfec.Number_of_years__c).intValue();
    for(integer i=0;i<totalYears;i++){
      tempfevent.RecordTypeId = rectype;
      tempfevent.Funding_Vehicle__c = fevent.Funding_Vehicle__c;
      tempfevent.Project__c = newfec.Project__c;
      tempfevent.Program__c = newfec.Program__c;
      system.debug('...pListValue...'+pListValue);

       tempfevent.Funding_Level__c = pListValue;
       tempfevent.Status__c = newfec.Status__c;
      tempfevent.Amount__c = newfec.Amount__c/totalYears ;
      tempfevent.Fiscal_Year__c = String.valueof(Integer.valueof(newfec.Fiscal_Year__c)+i);
      tempfevent.Number_of_years_of_the_Test_Event__c = newfec.Number_of_years__c;
      tempfevent.Budget_Expenses__c = newfec.Budget_Expenses__c;
      tempfevent.Series__c = seriesId;
      tempfevent.Staff_Count__c = newfec.Staff_Count__c;
      tempfevent.Test_Event_Controller__c = fec.Id;
      newfevenlist.add(tempfevent);
      tempfevent = new Test_Event__c();
   }
   insert newfevenlist;
 } 


for(Test_Event__c e: newfevenlist){
  fIds.add(e.Id);  
}
finalfevenlist =[Select f.Status__c, f.Series__c, f.Project__c, f.Program__c, f.Number_of_years_of_the_Test_Event__c, f.Name, f.Id, f.Fiscal_Year_Start_Date__c, f.Budget_Expenses__c, f.Amount__c,f.Funding_Vehicle__c,f.Funding_Type__c, f.Funding_Level__c,f.Fiscal_Year__c,f.Staff_Count__c,f.Test_Event_Controller__c   From Test_Event__c f where f.Id in:fIds and f.Status__c!='Cancelled'];
 return null;

}

public PageReference Cancel(){
  showButtons  = false;
  showFields = true;
  return null;
}

}





<apex:page Controller="NewEventController2">
<apex:form id="theform">
<apex:pageBlock title="New Funding Event" mode="edit" id="pblock">
  <apex:pageMessages id="messages"/>
  <apex:pageblockButtons location="top">
<apex:commandButton value="Submit" action="{!save}" reRender="result,fields,messages,theform" rendered="{!showButtons == true}">
</apex:commandButton>
 <apex:commandButton value="Cancel" action="{!cancel}" immediate="true" rendered="{!showButtons == true}" reRender="theform">
</apex:commandButton>
  <apex:commandButton value="Edit" action="{!Edit}" immediate="true" rendered="{!showFields == true}" reRender="theform">
</apex:commandButton>
</apex:pageblockButtons>
 <apex:outputPanel id="panel" >
  <apex:pageBlockSection id="fields">
  <apex:pageBlockSectionItem  rendered="{!showFields==false}">
   <apex:outputLabel value="Funding Level" for="flevel"/> 
   <apex:outputPanel styleClass="requiredInput" layout="block">
   <apex:outputPanel styleClass="requiredBlock" layout="block"/>
   <apex:selectList size="1" value="{!FundingLevelSelected}" styleClass="form-select"  id="flevel" label="Funding Level">
       <apex:selectOptions value="{!PickListValue}"/>
   </apex:selectList>
   </apex:outputPanel>
    </apex:pageBlockSectionItem>
    <apex:inputField value="{!newfec.Funding_Vehicle__c}" rendered="{!showFields==false}" required="true"/>
   <apex:inputField value="{!newfec.Program__c}" rendered="{!showFields==false}"/>
   <apex:inputField value="{!newfec.Project__c}" rendered="{!showFields==false}"/>
   <apex:inputField value="{!newfec.Status__c}" rendered="{!showFields==false}" required="true"/>
  <apex:inputField value="{!newfec.Fiscal_Year__c}" rendered="{!showFields==false}" required="true"/>
  <apex:inputField value="{!newfec.Number_of_Years__c}" rendered="{!showFields==false}" required="true"/>
  <apex:inputField value="{!newfec.Amount__c}" rendered="{!showFields==false}"/>
  <apex:inputField value="{!newfec.Budget_Expenses__c}" rendered="{!showFields==false}"/>
  <apex:inputField value="{!newfec.Staff_Count__c}" rendered="{!showFields==false}"/>
  <apex:outputField value="{!fec.Funding_Level__c}" rendered="{!showFields==true}"/>
<apex:outputField value="{!fec.Program__c}" rendered="{!showFields==true}"/>
  <apex:outputField value="{!fec.Project__c}" rendered="{!showFields==true}"/>
  <apex:outputField value="{!fec.Status__c}" rendered="{!showFields==true}"/>
  <apex:outputField value="{!fec.Fiscal_Year__c}" rendered="{!showFields==true}"/>
  <apex:outputField value="{!fec.Number_of_Years__c}" rendered="{!showFields==true}" />
  <apex:outputField value="{!fec.Amount__c}" rendered="{!showFields==true}"/>
 </apex:pageBlockSection>
  </apex:outputPanel>
  </apex:pageBlock>
    <apex:pageBlock id="result">
     <apex:pageBlockTable value="{!finalfevenlist}" var="fundevent">
     <apex:column headerValue="Action">
         <apex:commandLink action="{!saveEdit}" rendered="{!fundevent.Id == editEvent.Id}" rerender="panel,result">Save</apex:commandLink>&nbsp;&nbsp;
         <apex:commandLink action="{!cancelEdit}" rerender="result" rendered="{!fundevent.Id == editEvent.Id}">Cancel</apex:commandLink>
         <apex:commandLink action="{!editFundingEvents}" rerender="result" rendered="{!fundevent.Id != editEvent.Id}">Edit<apex:param name="editid" value="{!fundevent.id}"/></apex:commandLink>
      </apex:column>
            <apex:column headerValue="Funding Vehicle">
        <apex:InputField value="{!fundevent.Funding_Vehicle__c}" rendered="{!fundevent.Id == editEvent.Id}"/>
        <apex:outputField value="{!fundevent.Funding_Vehicle__c}" rendered="{!fundevent.Id != editEvent.Id}"/>  
     </apex:column>
     <apex:column headerValue="Program">
      <apex:InputField value="{!fundevent.Program__c}" rendered="{!fundevent.Id == editEvent.Id}"/>
      <apex:outputField value="{!fundevent.Program__c}" rendered="{!fundevent.Id != editEvent.Id}"/>  
     </apex:column>
     <apex:column headerValue="Project">
     <apex:InputField value="{!fundevent.Project__c}" rendered="{!fundevent.Id == editEvent.Id}"/>
     <apex:outputField value="{!fundevent.Project__c}" rendered="{!fundevent.Id != editEvent.Id}"/>   
     </apex:column>
     <apex:column headerValue="Status">
      <apex:InputField value="{!fundevent.Status__c}" rendered="{!fundevent.Id == editEvent.Id}"/>
      <apex:outputField value="{!fundevent.Status__c}" rendered="{!fundevent.Id != editEvent.Id}"/>
     </apex:column>  
     <apex:column headerValue="Fiscal Year">
     <apex:InputField value="{!fundevent.Fiscal_Year__c}" rendered="{!fundevent.Id == editEvent.Id}"/>
     <apex:outputField value="{!fundevent.Fiscal_Year__c}" rendered="{!fundevent.Id != editEvent.Id}"/>  
     </apex:column>
     <apex:column headerValue="Number of Years">
     <apex:InputField value="{!fundevent.Number_of_years_of_the_Funding_Event__c}" rendered="{!fundevent.Id == editEvent.Id}"/>
     <apex:outputField value="{!fundevent.Number_of_years_of_the_Funding_Event__c}" rendered="{!fundevent.Id != editEvent.Id}"/>
     </apex:column>
     <apex:column headerValue="Amount">
     <apex:InputField value="{!fundevent.Amount__c}" rendered="{!fundevent.Id == editEvent.Id}"/>
     <apex:outputField value="{!fundevent.Amount__c}" rendered="{!fundevent.Id != editEvent.Id}"/>
     </apex:column>
        </apex:pageBlockTable>       
  </apex:pageBlock>
</apex:form>
 </apex:page>
9
  • sf dev since the code is too long, just making wild guesshere. Does your debug show the newfe Id? Is the record getting inserted?
    – Rao
    Jan 31 '14 at 19:55
  • record is inserting..
    – sfdc
    Jan 31 '14 at 19:57
  • Also I see that at the end of the method you have used showPanel= true but never has that been used in the apex class/ VF page. what is this show panel doing
    – Rao
    Jan 31 '14 at 19:57
  • it is never used ..let me update the code
    – sfdc
    Jan 31 '14 at 19:58
  • What is the purpose of creating this newfe( it is same as newfec but missing the 'c') record, I see that you have just inserted a newfe( a local variable to the saveedit method) and used no where.
    – Rao
    Jan 31 '14 at 20:13
3

The short answer: change your rerender expression to:

rerender="{!$Component.theform.pblock.panel},result"

The detailed answer: The problem is your rerender expression, and it has to do with Visualforce's architecture and what I call namespacing components. When you specify a rerender expression like rerender="panel", you're actually specifying an element ID suffix, not the fully qualified element ID. The full ID is generated at compile-time by Visualforce, and is also used as the corresponding DOM element's "id" attribute (and also as its DOM "name" attribute if it's a form input). The full ID (e.g. something like "j_id0:j_id8:j_id33:panel") encodes the full path from the page root, through each enclosing namespacing component, to the actual element (in this case its name token is "panel" rather than an auto-generated "j_id" token, because you supplied an "id" attribute value of "panel").

When Visualforce is determining which elements on the page to rerender (after a POST-back action), it takes any partial element ID suffixes (like your "panel") in the rerender string (or string array), and tries to resolve them each to a fully-qualified ID. If it fails to resolve an ID, then it ignores that element of the rerender expression. The algorithm Visualforce uses to resolve these ID's is analogous to how block-scoping variable bindings are resolved in a typical imperative programming language -- and this is a very good choice, because this basic algorithm is sensible and well-known.

So what's happening here is that Visualforce is trying to resolve "panel" at the point of the rerender expression in your apex:pageBlockTable, which is in the namespace created by your 2nd apex:pageBlock (apex:form, apex:pageBlock, apex:component, apex:pageBlockTable, apex:dataTable, and apex:repeat are all namespacing components, but apex:outputPanel and other inline layout elements are not). However, your "panel" ID suffix is trying to match the element you have in your 1st apex:pageBlockTable, which is a totally different namespace that is NOT implicitly visible from the point of your rerender expression! Hence, Visualforce cannot resolve it to a fully qualified ID, and it doesn't get rerendered.

So what's the solution? In your case this is easy, since you're not crossing apex:component boundaries (I've had trouble referencing across apex:component boundaries, so I've developed my own JavaScript solutions for writing reusable components that can rerender specific parts inside other associated components): build a $Component reference chain that traverses to the target element. Simply go up to the closest common parent namespace (which IS visible from your rerender expression) and then from there go back down to your target element, 1 namespace at a time. The closest common parent is the apex:form, which you've already named "theform" (good). Now you go back down through the 1st pageBlock (which you've named "pblock", also good), and finally the target element, which you've named "panel". So you end up with the $Component expression:

$Component.theform.pblock.panel

Incidentally, I've not seen this issue nor Visualforce namespacing discussed in depth, yet it's been a significant pain-point for me in the past -- very frustrating!

And here's a fun example written in ECMAScript 6 to really drive home the analogy between Visualforce element namespacing and traditional block-scope variables:

var getPanel;
{
    // we use ECMAScript 6's let statement to declare block-scope variables (run in
    // FireFox Firebug console; Firefox has limited ECMAScript 6 support):
    let theform = 1;
    // we use an ECMAScript 6 code block to simulate a Visualforce namespacing
    // component's creation of a new namespace:
    {
        let pblock = 2;
        {
            let panel = 3;
            console.log("local access: " + panel); // prints "local access: 3"
            // ECMAScript function expressions can access block scope, while function
            // declarations cannot; since the 1st token on this next statement is not
            // "function", it is parsed as a function expression -- hence it can see
            // our let variables:
            getPanel = function() {
                return panel;
            };
        }
        let result = 4;
        {
            // the getPanel function can access the panel block-scope variable, because
            // it was defined in that scope!
            console.log("external access: " + getPanel()); // prints "external access: 3"
            try {
                // the "panel" block-scope variable is not accessible here, because it
                // was not defined in this block's namespace nor in an outer scope's
                // namespace:
                console.log(panel); // throws ReferenceError: panel is not defined
            } catch (e) {
                console.log(e); // prints the ReferenceError
            }
        }
    }
}
3
  • 1
    this was immensely helpful and explains why I had rerender problems in my own projects - usually resolved in frustration by just rerendering the whole form. Now I understand why. It makes sense if you look at the problem with an HTML DOM lens but lots of VF gets developed just with VF markup and you tend to forget about the underlying HTML and just think component ids are 'unique' and globally accessible. If it were possible, compiler errors/warnings would help avoid this scenario
    – cropredy
    Feb 1 '14 at 2:31
  • Hi, glad that was helpful! Yes, I absolutely agree with your comment about a compiler warning; Visualforce should issue such a warning when a $Component reference chain or a rerender token is not resolvable. It's ironic that in a dev platform that causes so much pain because it's too static and too strongly typed, in this one instance where we'd like the compiler's help, it does not yield any.
    – mulveling
    Feb 1 '14 at 6:10
  • I posted an Idea - success.salesforce.com/ideaView?id=08730000000l1CTAAY; feel free to embellish it
    – cropredy
    Feb 7 '14 at 1:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.