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>

39 comments:

  1. Thank you! This was very helpful.

    ReplyDelete
    Replies
    1. Hello Sir I want retrive 10 records in visualforce page with search button Accounts like (jon, heer, billclike, rams, geeet, siv, gramji, getea, sighn, oviessa) all records i retrived using with pageblock and Account name is one column and billing city second column I wand search button to add this vosual force page if i search "jo" to display jon related record only please give a code for search button in visualforce page

      Delete
  2. This helped debug a similar issue I was having. I had an apex:commandbutton calling a rerender of the outputText element it was inside of. The rerender failed because no ID was output to the HTML for the outputText element.

    I switched the rerender to the id of the apex:form element, and wa-la, it worked.

    Thanks for the suggestion.

    ReplyDelete
  3. Thanks for posting this. I had thought my problem was due to some combination of public/private/accessor settings when it actuality, it was good ole' AJAX. You just saved me another day of debugging.

    ReplyDelete
  4. fantastic post. Hope I could have been here earlier!
    Yesterday I tried so many things as my render was not working and finally got a solution at end of day.
    anyways fantastic post with source.

    ReplyDelete
  5. A+ post. Thanks for the info.

    ReplyDelete
  6. A brilliant blog indeed , its very clear and simple to understand. My Sincerer appreciation for a truly dedicated effort.

    ReplyDelete
  7. Had this happen before, don't mix your rendered and rerender!!!

    ReplyDelete
  8. Good one Bob. Fantastic analysis.

    ReplyDelete
  9. p.s- "div" is not accepeted I changed it to diva.
    Page should render component based on passed param each time. Once component rendered first time and component opens as overlay, upon closing component, page does not get refreshed. When calling "ViewRepDetail" next time it shows results from 1st rendered result from component. Any help would be much appreciated.
    Thanks-
    SG

    ReplyDelete
  10. can't post code.

    ReplyDelete
  11. Can you post this up to the developerforce visualforce board - that will allow you to post code.

    ReplyDelete
    Replies
    1. Bob, i am beginner and would like to know how did you debug to get the base code that you pasted in here and which helped you to find the issue and fixning it with double outputpanel.

      Delete
  12. Bob,
    my post goes here:

    http://boards.developerforce.com/t5/Visualforce-Development/Component-rendering-issue-with-actionFunction/td-p/446421

    Thanks
    SG

    ReplyDelete
  13. This comment has been removed by the author.

    ReplyDelete
  14. Bob,

    Is there any way I can do this using command button only and not using checkbox at all?

    I tried using without inputCheckbox and its not working ,












    Thanks
    Ali

    ReplyDelete
  15. This should work fine using a command button. Just set the Boolean property in the controller in the action method. I just used a checkbox for clarity.

    ReplyDelete
  16. Wow, Bob, thank you sooo much! I was well on my way to losing hair when I found this. Thank, thanks, thanks!

    ReplyDelete
  17. A good post, thanks, bob.

    ReplyDelete
  18. Thanks for Bob for this wonderful post. I was wondering why my page block table wasn't rendering.. Worked like charm!! Your a super star.. :)

    ReplyDelete
  19. Hi Bob,
    Nice Post

    Following is my reruirement
    i have 2 components in a page..

    1st component with all links -- Account,Contact
    2nd with all page block section -- Account section, contact section

    If user clicks on Account link ... only account section from 2nd component should be displayed
    If user clicks on Contact link ... only contact section from 2nd component should be displayed.

    I tried the above approach but didnt worked.
    You can check my post on

    http://salesforce.stackexchange.com/questions/17773/apex-componen
    t-rendering-pageblock-on-other-component/17776?noredirect=1#17776



    ReplyDelete
  20. sir i have developed a pege for adding contacts for account.in this i included save,cancel,addanotheraccount buttons .when addanotheraccount button is clicked same pageblock section has to be displayed as 2nd pageblock section

    ReplyDelete
  21. Very helpful info as always! Cheers, mate.

    ReplyDelete
  22. Thanks !! It was really helpful . I spent around 10 hours to solve the problem but it didnt work . Ur blog helped me !! Thanks again !! .

    ReplyDelete
  23. Bob -- One of the all-time most useful VF posts on the Internet. Every time I have some 'why doesn't this rerender' issue, I'm reminded of this post.

    ReplyDelete
  24. Grande Maestro!

    ReplyDelete
  25. Hi, I'm new at this... How would the controller look like? :|

    ReplyDelete
  26. Awesome....That worked

    ReplyDelete
  27. Thanks a ton for posting this. Helped to solve a issue that's been killing me for some time.

    ReplyDelete
  28. Bob - you know what's up! I ran into similar issue today and your post has resolved it. Thank you!

    ReplyDelete
  29. I am facing challenge for Custom css is not reflecting on rerender.

    ReplyDelete
  30. Thank you for the clear and succinct explanation. Much appreciated.

    ReplyDelete
  31. Great thanks, saved me tearing my hair out...

    ReplyDelete
  32. Best explanation ever!

    ReplyDelete
  33. Perfect! This solved my head-scratcher!

    ReplyDelete
  34. Eight years later, and this post is still helping people. Solved my problem today. Thanks, Bob!

    ReplyDelete
  35. Hi, I'm stuck at a situation where I have to display a lot of records on a visualforce page, and for that reason I've been trying to implement pagination. Also, I dont want the entire page to get refreshed but only the section where the records are being shown. I followed the original post and put it in another outputpanel, but it didnt seem to work. I could see the pagination work inside, but it wouldn't be rendered. Can anyone help?

    ReplyDelete