7

How would you pass a PageReference attribute to a custom component and have it assign to a variable on the component's controller? It seems like the assignTo attribute of apex:attribute does not work for ApexPages.Action or PageReference types. See the sample code below:

--- Page ---
<apex:page controller="pageController">
  <c:customComponent actionToInvoke="{!doSomething}"/>
</apex:page>

--- Page Controller ---
public class pageController{
  public PageReference doSomething(){
    return Page.SomeOtherPage;
  }
}

--- Component ---
<apex:component controller="componentController">
  <apex:attribute name="actionToInvoke" type="ApexPages.Action" assignTo="{!myAction}" required="false" description=""/>

  <!-- This button executes the supplied action as expected -->
  <apex:commandButton action="{!actionToInvoke}" value="Test1" />

  <!-- This button generates a visualforce error -->
  <apex:commandButton action="{!invokeAction}" value="Test2" />
</apex:component>

--- Component Controller ---
public class componentController{
  public ApexPages.Action myAction {get;set;}

  public PageReference invokeAction(){        
    // myAction is null, so this won't work
    return myAction.invoke();
  }
}
  • Could you potentially pass in a string attribute and resolve to a PageReference or Action via a lookup to a Map or a CustomSetting in the controller? – techtrekker Mar 8 '13 at 7:00
  • Yes, that is one workaround. I'll probably pass in a custom interface that has a PageReference method on it. – rycornell Mar 8 '13 at 13:33
  • This does look like a bug. Out of interest why do you want to invoke the action this way as apposed to directly via the button? I assume you want to do some pre or post processing around it? – Andrew Fawcett Mar 9 '13 at 11:54
  • Exactly. I would like to do some post processing after the button action executes. – rycornell Mar 11 '13 at 16:41
5

One mechanism for doing this would be to pass the page controller instance as the parameter to the component and then the component can call the page controller's methods itself via that reference.

Here is a functional example:

Page Controller

public with sharing class TestPageController {

    public TestPageController selfReference { get; set; }

    public Integer myInteger { get; set; }
    public String myString { get; set; }

    public TestPageController() {
        this.myInteger = 1;
        this.myString = String.valueOf(this.myInteger);
        selfReference = this;
    }

    public PageReference myStringAction() {
        // increment the integer and add it to the string
        this.myInteger += 1;
        this.myString += ', ' + String.valueOf(this.myInteger);
        return null;
    }
    public PageReference myRedirectAction() {
        // this essentially is doing a 'reset'
        PageReference pRef = Page.TestPage;
        pRef.setRedirect(true);
        return pRef;
    }
}

Component Controller

public with sharing class TestComponentController {

    public TestPageController thePageController { get; set; }

    public PageReference doPageControllerAction1() {
        return thePageController.myStringAction();
    }

    public PageReference doPageControllerAction2() {
        return thePageController.myRedirectAction();
    }
}

Component Markup (TestComponent.component)

<apex:component controller="TestComponentController" >
    <apex:attribute name="PageController" type="TestPageController" assignTo="{!thePageController}" required="true" description="the root page controller reference" />

    <p>The Component Body</p>
    <p>via local component controller methods by reference</p>
    <apex:commandButton action="{!doPageControllerAction1}" value="Fire Page Controller Action 1 (string) through component controller method" /><br />
    <apex:commandButton action="{!doPageControllerAction2}" value="Fire Page Controller Action 2 (redirect) through component controller method"/><br />

    <p>via Component Attribute's Name property reference</p>
    <apex:commandButton action="{!PageController.myStringAction}" value="Fire string action method through attribute name reference" /><br />

    <p>via direct reference through value set by 'assignTo' on attribute</p> 
    <apex:commandButton action="{!thePageController.myStringACtion}" value="Fire string action through controller reference" /><br />

    <p>data retrieved via component controller's pagecontroller reference</p>

    MyInteger: <apex:outputText value="{!thePageController.myInteger}" /><br />
    MyString: <apex:outputText value="{!thePageController.myString}" /><br />
</apex:component>

Page Markup (TestPage.page)

<apex:page controller="TestPageController" >
    <p>the myString value will be concatenated each time an action fires with the current myInteger value</p>
    <apex:form> 
        <c:TestComponent PageController="{!selfReference}" />
    </apex:form>
</apex:page>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.