[SalesForce] How to call controller extesion action from VF component

This question is similar to How to call a standard controller action of a VF page from a VF component, but there are two differences I see:

  • I'm not using a standard controller
  • the <apex:form> tags are in my component

I am trying to get the commandButton on the component to call the addMethod method on my extension. For whatever reason, this isn't happening. Nothing shows in the debug logs, so it doesn't appear to be working. There are no errors or exceptions thrown.

Should this be possible?

Update: The page uses an apex:repeat element, there's an onClick on the commandButton, the rendered value looks at the record type

My page

<apex:page standardController="Custom_Object__c" extensions="CustomObjectExtension">
    ... some content
    <apex:repeat value="{!childObjects}" var="cObject">
        <c:componentWithForm addMethodAction="{!addMethod}" rendered="{!cObject.RecordType.Name == 'My Record Type'} />
    </apex:repeat>
    ... more content
</apex:page>

Where the childObjects in the repeat element is a List

My component

<apex:component>
    <apex:attribute name="addMethodAction" type="ApexPages.Action" ... />
    <apex:form>
        <apex:inputText ... />
        <apex:commandButton onclick="return someFunction();" action="{!addMethodAction}" />
    </apex:form>
</apex:component>

My extension

public class CustomObjectExtension
{
    public List<Child_Object__c> childObjects {get; set;}

    public CustomObjectExtension(ApexPages.StandardController stdController)
    {
        .. do stuff
        childObjects = [SELECT ... FROM Child_Object__c];
    }

    public PageReference addMethod()
    {
        .. do stuff
    }
}

Best Answer

I found 3 strange reasons why the addMethod wasn't being called. I'd love to hear from anyone that has any ideas on the why, or where I might be wrong.

OnClick attribute

For some reason the onClick attribute on the apex:commandButton was preventing it being called. This includes if I left it empty, or just had a 'return true;' or 'return false;' in there.

No actionRegion

When the component was being called from within an apex:repeat element, the component needed an actionRegion element for it to correctly call the addMethod.

e.g.

<apex:component>
    <apex:attribute name="addMethodAction" type="ApexPages.Action" ... />
    <apex:form>
        <apex:actionRegion>
            <apex:inputText ... />
            <apex:commandButton onclick="return someFunction();" action="{!addMethodAction}" />
        </apex:actionRegion>
    </apex:form>
</apex:component>

rendered attribute on the component

This is really weird. When calling the component, the way the rendered attribute is populated seems to matter. For the component to render, the result of the rendered expression must be true, so you'd assume that if the button is on tha page, the behaviour should be the same.

That doesn't appear to be the case however. For some reason, if the rendered attribute is populated as the result of a variable-to-string comparison, addMethod isn't called.

I had: rendered="{!cObject.RecordType.Name == 'My Record Type'}" but this didn't work. The button would be displayed, but the addMethod method would not be called.

Changing it to rendered="true" worked. Delving deeper, 1==1 worked, '1'=='1' worked, today()==today() worked.

cObject.myTextField__c == 'expected value' did not work.

cObject.myBooleanField__c did work.

In the end I had to create a formula field on the Custom_Object__c that returned true if RecordType.Name == 'My Record Type'

I then called the rendered attribute as follows: rendered="{!cObject.myBooleanFormulaField__c}"


Has anyone seen behaviour like this? Does anyone have any idea why this is happening? Am I going crazy?