Tuesday, June 18, 2013

Custom Component Controllers and using assignTo

So I have been working with components lately and have been pretty aggravated that I couldn't seem to get the assignTo to work correctly. So I followed the example showen in the documentation (Custom Component Controllers) word for word, and it worked.. but not really.  Once I tried switching the get/set to the way I prefer public String controllerValue {get; set;} it stopped working. I also noticed that if I was to put anything in the constructor it access it, it would create a null error. For example, if you were to use the same example as in the documentation and changed the class to:

public with sharing class sgf_ComponentAssignToIssue {

  public String controllerValue;
    
  public void setControllerValue (String s) {
    controllerValue = s.toUpperCase();
  }
    
  public String getControllerValue() {
    return controllerValue;
  }

  public sgf_ComponentAssignToIssue() {
    if (String.isNotBlank(controllerValue)) {
      controllerValue.toLowerCase();
      return;
    }
    ApexPages.addMessage(new ApexPages.Message(
      ApexPages.Severity.ERROR, 
      'string is blank'
    ));
  }

}

and change the page to:

<apex:component controller="sgf_ComponentAssignToIssue">
  <apex:attribute name="componentValue" description="Attribute on the component." type="String" required="required" assignTo="{!controllerValue}" />
    <apex:pageBlock title="My Custom Component">
      <p>
        <code>componentValue</code> is "{!componentValue}"
        <br/>
        <code>controllerValue</code> is "{!controllerValue}"
      </p>
    </apex:pageBlock>
    Notice that the controllerValue has been upper cased using an Apex method.

  <!-- just adding the following -->
  <br />
  <apex:pageMessages id="messages" />

</apex:component>

the page will error:


If I change the class to:

public with sharing class sgf_ComponentAssignToIssue {

  public String controllerValue {
    get {return controllerValue.toUpperCase();} 
    set;
  }
    
  public sgf_ComponentAssignToIssue() {
    if (String.isNotBlank(controllerValue)) {
      controllerValue.toLowerCase();
      return;
    }
    ApexPages.addMessage(new ApexPages.Message(
      ApexPages.Severity.ERROR, 
      'string is blank'
    ));
  }
}

and leave the page as is, the page will now error:


If I change it so the class looks like this:

public with sharing class sgf_ComponentAssignToIssue {

  public String controllerValue {
    get;
    set {controllerValue = value.toUpperCase();}
  }
    
  public sgf_ComponentAssignToIssue() {
    if (String.isNotBlank(controllerValue)) {
      controllerValue.toLowerCase();
      return;
    }
    ApexPages.addMessage(new ApexPages.Message(
      ApexPages.Severity.ERROR, 
      'string is blank'
    ));
  }

}

The page will work again, but still nothing works in the constructor. And if I change it to say, an Id and update the class to:

public with sharing class sgf_ComponentAssignToIssue {

  public Id controllerValue {get; set;}
  public Account passedAccount {get; set;}
    
  public sgf_ComponentAssignToIssue() {
    if (String.isNotBlank((String)controllerValue)) {
      passedAccount = new Account(Id = controllerValue);
      return;
    }
    ApexPages.addMessage(new ApexPages.Message(
      ApexPages.Severity.ERROR, 
      'Id is blank'
    ));
  }

}

and the page to pass the Id to the controller, you get:
So you can see that the controller does effect the variable but still since I can not use it in the constructor I cant really use it in the component to do anything on load... 

My Question is:
Why cant the class constructor or the getter access the variable being passed from the assignTo?

4 comments:

  1. > Why cant the class constructor or the getter access the variable being passed from the assignTo?

    Salesforce will need to create an instance of your class before the assignTo values can be passed to the properties. The class constructor has to complete before the properties can be assigned. Hence you can't get to the assignTo values in the constructor.

    ReplyDelete
  2. so how can you use something passed to the controller? I need to pass an account Id and then populate based off that.

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

    ReplyDelete
  4. The constructor happens before the setters are called. Thus the values are null during the constructor call.
    I hope this helps.

    ReplyDelete