Views: 491
In a simple, straightforward programming situation, you would assume that functions are executed when they are seemingly called. When you are rendering a Visual Force page in Salesforce, things seem to be a bit mixed up. Though it seems counter-intuitive, it is understandable what happens.
Let’s take a simple example of a Visual Force page with a controller.
Page (atest):
<apex:page controller="Atest"> Parameter: {!parameter} <br /> Parameter2: {!parameter2} <br /> Parameter: {!parameter} <br /> Parameter2: {!parameter2} <br /> Parameter: {!parameter} <br /> Parameter2: {!parameter2} <br> </apex:page>
Controller:
public class Atest { private Integer parameter; public Atest () { System.debug ('Constructor called.'); parameter = 1; } public Integer getParameter () { System.debug ('getParameter'); parameter = parameter + 1; return parameter; } public Integer getParameter2 () { System.debug ('getParameter2'); parameter = parameter + 1; return parameter; } public PageReference nextPage () { PageReference page1 = new PageReference('/apex/atest2'); Blob b = page1.getContentAsPDF(); PageReference page2 = new PageReference('/apex/atest2'); b = page2.getContentAsPDF(); PageReference page3 = new PageReference('/apex/atest2'); return page3; } }
{!parameter} is a reference to the method getParameter () and {!parameter2} a reference to getParameter2 (). Ignore the method nextPage () for now…
So what you might expect is that the Visual Force renderer calls getParameter (). This increases the variable parameter by 1 and returns its new value. We do see the output “Parameter: 2” – as expected. Then the renderer calls getParameter2 (). This again increases the variable parameter by 1 and returns its new value. We do see the output “Parameter2: 3” – as expected.
Next, we want “parameter” again – seemingly a call to the method getParameter (). But now the method is not actually executed; parameter is not increased anymore. We get the outputs “Parameter: 2” and “Parameter2: 3” again and again, no matter how many times we think the method is called.
Now for the second part in the controller above, we need the VF page atest2, which is virtually the same, except that it is a different file. Also, for convenience to call the method in our class, add
<apex:form> <apex:commandButton action="{!nextPage}" value="next page" /> </apex:form>
to the page atest. When you now click on “next page”, the page atest2 is created 3 times. To make sure that it is actually rendered, we get the content of the page as a pdf, and the third time, the page is returned as a PageReference. Therefore you are transported to the page atest2.
What you now see is “Parameter: 4” and “Parameter2: 5”. Even though we have rendered the page atest2 3 times, the variable parameter has only been increased by 1 two times.
This is because the renderer works in the same context for all 3 times it renders atest2. getParameter () and getParameter2 () are both called exactly once, and that only, because we are rendering a page in a new context – the call to the method nextPage (). You could even create the pages atest3 and atest4, have them rendered after each other (in one method), and “Parameter” and “Parameter2” will be the same value for each rendered page.
Any output of a method is directly cached, and the method is not called again, except for if you force a rerender – because that is what re-rendering is for. If you know that values will change, you have to instruct Visual Force to do a new rendering.
To get around this, make sure that you create a new context for a new page with changing information. The easiest way to do so is IMHO to create a controller instance for every page that needs to be rendered, and this in turn can be done by having a different controller for the subsequent pages.
tl;dr:
Do not change the information of a variable or method during one rendering context. Have all information be calculated before anything is actually rendered, and do not change information when using a get-method. If information changes due to user input, have the sections that show information based on the input rerendered when necessary.
Overall: within one context the VF renderer will always call any getter only once.