Setter method in VF component being called after the constructor has retured

VF page

<apex:page>
  <c:MyCustomComponent someString="hello"/>
</apex:page>

MyCustomComponent (component)

<apex:component controller="MyCustomComponentController">
<apex:attribute name="someString" assignTo="{!receivedString}" type="String"/>
..
some more code
..
</apex:component>

MyCustomComponentController (component controller)

public with sharing class MyCustomComponentController{

    public String receivedString {get;set;}

    public MyCustomComponentController() {
        System.debug(receivedString); 
    }

    public initializeComponent() {
        System.debug(receivedString); 
    }
}

The problem is in the first System.debug inside the constructor the receivedString is null. So the constructor is being called before the receivedString’s value can be set.

Is there any workaround for this.

Appreciate your help.

Answer

What you have observed is consistent with the documented Order of Execution for Visualforce Page Get Requests. It will always be not yet set in the constructor.

Order of Execution for Visualforce Page Get Requests

  1. The constructor methods on the associated custom controller or controller extension classes are called, instantiating the controller
    objects.
  2. 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.
  3. 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.
  4. If the page contains an component, all of the information necessary to maintain the state of the database between
    page requests is saved as an encrypted view state. The view state is
    updated whenever the page is updated.
  5. The resulting HTML is sent to the browser. If there are any client-side technologies on the page, such as JavaScript, the browser
    executes them.

One workaround is to do the intialization inside of your setter.

public with sharing class MyCustomComponentController {

    public Boolean initialized { get; set; }

    public String receivedString { 
        get;
        set {
            receivedString = value;
            if (!initialized) {
                initializeThatDependsOnReceivedString();
                initialized = true;
            }
        }
    }

    public MyCustomComponentController() { System.debug(receivedString); }
    public initializeThatDependsOnReceivedString() { System.debug(receivedString); }  
}

Or, you could put the initialization in the getter.

public String receivedString { 
    get {
        if (!initialized) {
            initializeThatDependsOnReceivedString();
            initialized = true;
        }
        return receivedString;
    }
    set;
}

It starts to get a little bit unwieldy if you have some initialization that depends on many attributes being set.

Alternatively, you could create an actionFunction in the component that you call after the component has loaded and do the one time initialization in it. You would just need to make sure that you code the component VF so that the actionFunction is only invoked one time.

Attribution
Source : Link , Question Author : codeinprogress , Answer Author : Peter Knolle

Leave a Comment