I've hacked this small example of the unexpected order based on Order of Execution for Visualforce Page Get Requests. From the linked docs (my empahsis):
- The constructor methods on the associated custom controller or controller extension classes are called, instantiating the controller objects.
- If the page contains any custom components, they are created and the constructor methods on any associated custom controllers or controller extensions are executed. If attributes are set on the custom component using expressions, the expressions are evaluated after the constructors are evaluated.
- The page then executes any assignTo attributes on any custom components on the page. After the assignTo methods are executed, expressions are evaluated, the action attribute on the component is evaluated, and all other method calls, such as getting or setting a property value, are made.
- ...
This isn't lining up with what I'm seeing in the debug logs.
6 USER_DEBUG [4] DEBUG myController constructor called. Visualforce page controller
9 USER_DEBUG [8] DEBUG myController actionMethod Visualforce page action method called
15 USER_DEBUG [11] DEBUG componentController constructor called.
19 USER_DEBUG [5] DEBUG selectedValue set in componentController
24 USER_DEBUG [5] DEBUG selectedValue set in componentController
Note how the actionMethod on the parent Visualforce page is called before the component constructor and any of the custom component assignTo properties are set.
Basically, why is the page controllers action method being called immediately after the constructor and before the components are ready?
I've got components where I want to call methods on them from the controllers action method. This, of course, requires them to have been constructed first.
These are all using v36.0 from Spring '16.
Component Controller:
public class componentController {
public String selectedValue {
get;
set {
System.debug(LoggingLevel.Debug, 'selectedValue set in componentController');
selectedValue = value;
}
}
public componentController() {
System.debug(LoggingLevel.Debug, 'componentController constructor called.');
}
}
Component:
<apex:component controller="componentController">
<apex:attribute name="value" type="String" description="Sample component." assignTo="{!selectedValue}"/>
<p>
Value = {!value}<br/>
selectedValue = {!selectedValue}<br/>
</p>
</apex:component>
Controller:
public with sharing class myController {
public myController() {
System.debug(LoggingLevel.Debug, 'myController constructor called. Visualforce page controller');
}
public void actionMethod() {
System.debug(LoggingLevel.Debug, 'myController actionMethod Visualforce page action method called');
}
}
Visualforce page:
<apex:page controller="myController" action="{!actionMethod}">
<apex:messages />
<apex:pageBlock title="Component page block">
<c:editMode value="{!$CurrentPage.parameters.key}"/>
</apex:pageBlock>
</apex:page>