Showing posts with label Salesforce Visualforce conditional render rerender failure outputpanel. Show all posts
Showing posts with label Salesforce Visualforce conditional render rerender failure outputpanel. Show all posts

Saturday, 19 February 2011

Visualforce Re-rendering Woes

A couple of days ago I was tripped up by re-rendering for what seemed like the hundredth time.  I'd created a page containing a conditionally rendered component based on a boolean field from the controller. This field was initially set to false, so the component didn't appear.  The value could then be changed on the page via a checkbox and clicking a button would refresh a section of the page whereupon the component would magically appear.  Here's a much reduced version of the Visualforce markup.

<apex:page controller="RerenderController">
<h1>Rerender Example</h1>
<apex:form >
  <apex:outputPanel id="datePanel" rendered="{!showdate}"> 
    <apex:outputText value="Date : {!todaysDate}"/>
  </apex:outputPanel>
  <div>
     Show Date? <apex:inputCheckbox value="{!showDate}"/>
  </div>
  <apex:commandButton value="Submit" rerender="datePanel"/>
</apex:form>
</apex:page>

I changed the value, clicked the button and hey presto - nothing changed!  I went the usual route of adding debug to the controller, which showed that the showDate value as being updated correctly.  Maybe there was an error that we being hidden due to the re-rendering, so out came the rerender attribute on the command button. No sign of any error and things started behaving as expected.  At this point I remembered why this is happening.

Adding the rerender attribute back in and viewing the source for the generated page shows the following:

<h1>Rerender Example</h1> 
<form id="j_id0:j_id2" name="j_id0:j_id2" method="post" action="https://kab-tutorial.na6.visual.force.com/apex/RerenderExample" enctype="application/x-www-form-urlencoded"> 
<input type="hidden" name="j_id0:j_id2" value="j_id0:j_id2" /> 
 
  <div> 
     Show Date?<input type="checkbox" name="j_id0:j_id2:j_id5" /> 
  </div><input class="btn" id="j_id0:j_id2:j_id7" name="j_id0:j_id2:j_id7" onclick="A4J.AJAX.Submit('j_id0:j_id2',event,{'similarityGroupingId':'j_id0:j_id2:j_id7','parameters':{'j_id0:j_id2:j_id7':'j_id0:j_id2:j_id7'} } );return false;" value="Submit" type="button" /><div id="j_id0:j_id2:j_id8"></div><input type="hidden"  id="com.salesforce.visualforce.ViewState" name="com.salesforce.visualforce.ViewState" value="..." />
<form>

Notice that there is no element with an id containing the text datePanel, as the output panel isn't rendered due to the showDate value being false. Thus even though the showDate value is set to true, when the Ajax request completes, the element that should be re-rendered doesn't exist and therefore nothing changes.

The solution is to nest the conditionally rendered output panel inside another output panel and change the command button to rerender that. The containing output panel will always be present on the page and thus the Ajax request will be able to update it on completion. The inner component may or may not be rendered depending on the value of showDate.

Below is the revised Visualforce markup that behaves as desired:

<apex:page controller="RerenderController">
<h1>Rerender Example</h1>
<apex:form >
  <apex:outputPanel id="datePanelContainer">
    <apex:outputPanel id="datePanel" 
        rendered="{!showdate}"> 
      <apex:outputText value="Date : {!todaysDate}"/>
    </apex:outputPanel>
  </apex:outputPanel>
  <div>
     Show Date? <apex:inputCheckbox value="{!showDate}"/>
  </div>
  <apex:commandButton value="Submit" 
    rerender="datePanelContainer"/>
</apex:form>
</apex:page>