7

Fairly new to creating Visualforce components and I'm attempting to reuse some of my front-end mark up with multiple components that used in a parent component. At first I question if this was possible and in its most basic application it appears to be, but now I need to determine the limits of this approach.

For example, I've been able to pass parameters from the parent component controller to the child component as attributes like so:

Parent Component:

<apex:component controller="parentController">    
    <apex:variable var="myVar" value="IsTrue" />
    <c:ChildComponent data-attribute="myVar">
</apex:component>

Child Component:

<apex:component> <!--no controller -->
    <apex:attribute name="data-attribute" description="Used to determine if the widget data is fully loaded and available" type="Boolean" required="true"/>
    <apex:variable var="childVariable" value="{!data-attribute}"/>
    <apex:outputText>{!childVariable}</apex:outputText>    
</apex:component>

But this basic example does determine if I can do the following:

  1. Can I use the controller?
    • Perhaps set a controller and pass the parent controller to the constructor or some other method?
    • Can I use getter/setters or controller methods?
    • If I add a controller to the child I suppose that creates its own instance?
  2. If I have a command button can I rerender an element outside the context of the child component (in the parent)?

Are these things possible and if so how? Is it something I will need to accomplish through JavaScript or some other solution?

  • (1) Passing controllers amongst components - see salesforce.stackexchange.com/a/102594/2602; (2) rerendering parent components - try passing as an attribute the id of the "thing" that needs rerendering to the child component – cropredy Dec 21 '15 at 23:51
10

Can use the controller?

Perhaps set a controller and pass the parent controller to the construct or somehow?

Yes, you may use the controller using apex:attribute. The data type of the attribute will be the name of the class you're passing in. You can use both the standard controller and any other controllers you'd like. As a trivial example:

Page

<apex:page standardController="Account" extensions="ComCtrl">
    <c:myComp standardController="{!ComCtrl.pageController}" />
</apex:page>

Controller

public class ComCtrl {
    public ApexPages.StandardController pageController { get; set; }
    public ComCtrl() { /* Required for component use */ }
    public ComCtrl(ApexPages.StandardController ctrl) {
        pageController = ctrl;
    }
}

Component

<apex:component controller="ComCtrl">
    <apex:attribute name="standardController" type="ApexPages.StandardController" assignTo="{!pageController}" description="" />
</apex:component>

Can I use getter/setters or controller methods?

Once you have a reference to the controller, you can use it any way you'd like, but it'll appear differently, because you have to reference it via the attribute or assignTo value (e.g. action="{!parentController.someAction}").

By way of example:

Within Component

<apex:commandButton value="Save" action="{!pageController.save}" />

If I add a controller to the child I suppose that creates its own instance?

Yes, each time you reference a class, it creates a new instance of that class. Multiple instances can happily co-exist within the same page/component hierarchy. A trivial example:

Controller

public class Counter {
    public Integer value { get; set; }
    public String[] counters { get; set; }
    public Counter() {
        value = 0;
        counters = 'I want more counters on the page.'.split(' ');
    }
    public void increment() {
        value++;
    }
}

Component

<apex:component controller="counter">
    {!value} <apex:commandButton value="+1" action="{!increment}" reRender="form" />
</apex:component>

Page

<apex:page controller="counter">
    <apex:form id="form">
        <table>
            <apex:repeat value="{!counters}" var="ctr">
                <tr><td>{!ctr}</td><td>
                    <c:counter /></td>
                </tr>
            </apex:repeat>
        </table>
    </apex:form>
</apex:page>

If I have a command button can I rerender an element outside the context of the child component (in the parent)?

Yes. As long as you use the correct value in the reRender attribute, reRendering outside the current component does work. I'd take some care about doing this, especially if a component is in a repeat tag, nested with other components, etc. You might end up reRendering something you didn't intend to. See the "counter" example, above, for a case where I reRender the entire form directly from the component.

Also, you can use the slightly odder version where you reRender using an actionFunction outside your component:

Page

<apex:page ...>
    <apex:form id="form">
        <apex:actionFunction name="redrawPage" reRender="form" />
        <c:someComponent />
    </apex:form>
</apex:page>

Component

<apex:commandButton action="{!doSomething}" reRender="" onComplete="redrawPage()" />

This design may double the required round-trips, though, so I'd use this sparingly. However, you could use it to a useful effect, such as doing something from within the component without actually establishing inter-component communications at the controller level (they cooperate strictly through JavaScript calls). This can sometimes improve performance by reducing view state, etc.

  • 1
    Calling your extension Ctrl? Still, solid, thorough answer. – Adrian Larson Dec 22 '15 at 0:34
  • 1
    @AdrianLarson I actually usually don't distinguish between controllers and extensions by name, because an extension happens to be a specialized type of controller (a controller being code that directs business logic). In fact, other than the one-parameter construction, they behave exactly the same. Regardless, I felt that Ctrl was appropriate here, because the class actually plays a dual role as both extension and controller. – sfdcfox Dec 22 '15 at 2:38

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.