Tweet |
Here's an example of how this component can help track down problems when rerendering parts of a page. The following page simply presents a button to invoke an action method that increments the counter:
<apex:page controller="PageMessages"> <apex:form > <apex:pageBlock title="Page Messages Test 1"> <apex:pageBlockButtons > <apex:commandButton value="Click Me" action="{!click}" rerender="counter"/> </apex:pageBlockButtons> <apex:outputLabel value="Count = " /> <apex:outputText value="{!countVal}" id="counter"/> </apex:pageBlock> </apex:form> </apex:page>
The controller contrives to produce an error rather than increment the counter:
public with sharing class PageMessages { public Integer countVal {get; set;} private Boolean fakeError=true; public PageMessages() { countVal=1; } public void click() { if (fakeError) { ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, 'Fake Error')); } else { countVal++; } } }
The page when rendered is as follows:
Opening the page in a browser window: and clicking the 'Click Me' button results in no change to the count value, and as the rerender attribute turns the command into an AJAX request, it looks like clicking the button has no effect whatsoever. In this case I can turn on debug logging and see that an error message is being added to the page:
14:37:19.021 (21244000)|CODE_UNIT_STARTED|[EXTERNAL]|01p80000000cOqp|PageMessages invoke(click) 14:37:19.021 (21302000)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:6 14:37:19.021 (21322000)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:524 14:37:19.021 (21338000)|METHOD_ENTRY|[1]|01p80000000cOqp|PageMessages.PageMessages() 14:37:19.021 (21345000)|STATEMENT_EXECUTE|[1] 14:37:19.021 (21357000)|SYSTEM_MODE_ENTER|false 14:37:19.021 (21370000)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:5 14:37:19.021 (21376000)|STATEMENT_EXECUTE|[1] 14:37:19.021 (21385000)|SYSTEM_MODE_EXIT|false 14:37:19.021 (21394000)|METHOD_EXIT|[1]|PageMessages 14:37:19.021 (21443000)|SYSTEM_MODE_ENTER|false 14:37:19.021 (21450000)|HEAP_ALLOCATE|[12]|Bytes:5 14:37:19.021 (21456000)|STATEMENT_EXECUTE|[11] 14:37:19.021 (21465000)|STATEMENT_EXECUTE|[13] 14:37:19.021 (21469000)|STATEMENT_EXECUTE|[14] 14:37:19.021 (21612000)|HEAP_ALLOCATE|[14]|Bytes:10 14:37:19.021 (21689000)|SYSTEM_METHOD_ENTRY|[14]|ApexPages.addMessage(ApexPages.Message) 14:37:19.021 (21697000)|ENTERING_MANAGED_PKG| 14:37:19.021 (21728000)|VF_PAGE_MESSAGE|Fake Error 14:37:19.021 (21738000)|SYSTEM_METHOD_EXIT|[14]|ApexPages.addMessage(ApexPages.Message) 14:37:19.021 (21746000)|SYSTEM_MODE_EXIT|false 14:37:19.021 (21775000)|CODE_UNIT_FINISHED|PageMessages invoke(click)
Its a lot easier just to add an <apex:pagemessages/> component to the page and rerender that as well:
<apex:page controller="PageMessages"> <apex:pageMessages id="msgs"/> <apex:form > <apex:pageBlock title="Page Messages Test 1"> <apex:pageBlockButtons > <apex:commandButton value="Click Me" action="{!click}" rerender="counter,msgs"/> </apex:pageBlockButtons> <apex:outputLabel value="Count = " /> <apex:outputText value="{!countVal}" id="counter"/> </apex:pageBlock> </apex:form> </apex:page>
which displays the error upon clicking the button:
Another scenario where its pretty much impossible to locate the problem without an <apex:pageMessages/> component is where there is a required field on the page:
<apex:page controller="PageMessages"> <apex:pageMessages id="msgs"/> <apex:form > <apex:pageBlock title="Page Messages Test 1"> <apex:pageBlockButtons > <apex:commandButton value="Click Me" action="{!click}" rerender="counter,msgs"/> </apex:pageBlockButtons> <apex:outputLabel value="Text1 = " /> <apex:inputText value="{!text}" required="true"/> <br/> <apex:outputLabel value="Count = " /> <apex:outputText value="{!countVal}" id="counter"/> </apex:pageBlock> </apex:form> </apex:page>
This time the controller doesn't fake an error, the counter value is simply updated:
public with sharing class PageMessages { public Integer countVal {get; set;} public String text {get; set;} public PageMessages() { countVal=1; } public void click() { countVal++; } }
As the required component isn't an <apex:inputField/>, there is no decoration of the element to indicate that it is required. Clicking the 'Click Me' button once again appears to do nothing.
Checking the log this time reveals nothing that can help. The click method simply isn't being called:
25.0 APEX_CODE,FINEST;APEX_PROFILING,INFO;CALLOUT,INFO;DB,INFO;SYSTEM,DEBUG;VALIDATION,INFO;VISUALFORCE,INFO;WORKFLOW,INFO 15:06:55.036 (36399000)|EXECUTION_STARTED 15:06:55.036 (36462000)|CODE_UNIT_STARTED|[EXTERNAL]|06680000000Tmbw|VF: /apex/kab_tutorial__PageMessage1 15:06:55.046 (46438000)|CODE_UNIT_STARTED|[EXTERNAL]|01p80000000cOqp|PageMessages <init> 15:06:55.046 (46470000)|SYSTEM_MODE_ENTER|true 15:06:55.047 (47466000)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:8 15:06:55.047 (47490000)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:552 15:06:55.047 (47513000)|METHOD_ENTRY|[1]|01p80000000cOqp|PageMessages.PageMessages() 15:06:55.047 (47539000)|STATEMENT_EXECUTE|[1] 15:06:55.047 (47659000)|SYSTEM_MODE_ENTER|false 15:06:55.047 (47678000)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:5 15:06:55.047 (47694000)|STATEMENT_EXECUTE|[1] 15:06:55.047 (47707000)|SYSTEM_MODE_EXIT|false 15:06:55.047 (47720000)|METHOD_EXIT|[1]|PageMessages 15:06:55.047 (47763000)|VARIABLE_SCOPE_BEGIN|[5]|this|KAB_TUTORIAL.PageMessages|true|false 15:06:55.047 (47808000)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:12 15:06:55.047 (47845000)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:12 15:06:55.047 (47889000)|VARIABLE_ASSIGNMENT|[5]|this|{}|0x549e58c6 15:06:55.047 (47910000)|SYSTEM_MODE_ENTER|false 15:06:55.047 (47921000)|HEAP_ALLOCATE|[2]|Bytes:5 15:06:55.047 (47935000)|STATEMENT_EXECUTE|[1] 15:06:55.047 (47944000)|HEAP_ALLOCATE|[2]|Bytes:5 15:06:55.047 (47956000)|STATEMENT_EXECUTE|[2] 15:06:55.047 (47974000)|STATEMENT_EXECUTE|[3] 15:06:55.047 (47991000)|STATEMENT_EXECUTE|[6] 15:06:55.048 (48000000)|STATEMENT_EXECUTE|[7] 15:06:55.048 (48042000)|METHOD_ENTRY|[7]|01p80000000cOqp|KAB_TUTORIAL.PageMessages.__sfdc_countVal(Integer) 15:06:55.048 (48098000)|HEAP_ALLOCATE|[2]|Bytes:12 15:06:55.048 (48122000)|HEAP_ALLOCATE|[2]|Bytes:12 15:06:55.048 (48142000)|VARIABLE_ASSIGNMENT|[-1]|this|{}|0x549e58c6 15:06:55.048 (48155000)|HEAP_ALLOCATE|[2]|Bytes:8 15:06:55.048 (48190000)|VARIABLE_ASSIGNMENT|[-1]|value|1 15:06:55.048 (48205000)|HEAP_ALLOCATE|[2]|Bytes:8 15:06:55.048 (48231000)|VARIABLE_ASSIGNMENT|[2]|this.countVal|1|0x549e58c6 15:06:55.048 (48260000)|METHOD_EXIT|[7]|01p80000000cOqp|KAB_TUTORIAL.PageMessages.__sfdc_countVal(Integer) 15:06:55.048 (48275000)|SYSTEM_MODE_EXIT|false 15:06:55.048 (48292000)|CODE_UNIT_FINISHED|PageMessages <init> 15:06:55.048 (48814000)|VF_SERIALIZE_VIEWSTATE_BEGIN|06680000000Tmbw 15:06:55.050 (50548000)|VF_SERIALIZE_VIEWSTATE_END 15:06:55.440 (54027000)|CUMULATIVE_LIMIT_USAGE 15:06:55.440|LIMIT_USAGE_FOR_NS|KAB_TUTORIAL| Number of SOQL queries: 0 out of 100 Number of query rows: 0 out of 50000 Number of SOSL queries: 0 out of 20 Number of DML statements: 0 out of 150 Number of DML rows: 0 out of 10000 Number of script statements: 3 out of 200000 Maximum heap size: 0 out of 6000000 Number of callouts: 0 out of 10 Number of Email Invocations: 0 out of 10 Number of fields describes: 0 out of 100 Number of record type describes: 0 out of 100 Number of child relationships describes: 0 out of 100 Number of picklist describes: 0 out of 100 Number of future calls: 0 out of 10 15:06:55.440|CUMULATIVE_LIMIT_USAGE_END 15:06:55.054 (54063000)|CODE_UNIT_FINISHED|VF: /apex/kab_tutorial__PageMessage1 15:06:55.054 (54077000)|EXECUTION_FINISHED
In fact what has happened is the client side validation has failed and the page is simply redrawn. However, at this point its very easy to start doubting your code and rewriting it randomly - especially if its more complex than my simple example. Simply adding an <apex:pageMessages/> component that is rerendered avoids all this:
<apex:page controller="PageMessages"> <apex:pageMessages id="msgs"/> <apex:form > <apex:pageBlock title="Page Messages Test 1"> <apex:pageBlockButtons > <apex:commandButton value="Click Me" action="{!click}" rerender="counter,msgs"/> </apex:pageBlockButtons> <apex:outputLabel value="Text1 = " /> <apex:inputText value="{!text}" required="true"/> <br/> <apex:outputLabel value="Count = " /> <apex:outputText value="{!countVal}" id="counter"/> </apex:pageBlock> </apex:form> </apex:page>
Clicking the button this time shows the validation error.
As an aside, due to the required element not being an <apex:inputField/>, the error message is not particularly helpful. For details on how to improve this, take a look at one of my older posts.
Just want to say thanks for this. Solved my problem.
ReplyDelete