Why can't we call controllers parameterized methods directly from Visualforce

While remoting is an option, it changes the architecture of your page and controller into a stateless model (your methods have to be static) so you have no access to the page state. Also for a formatting requirement, which you appear to have, could be quite expensive to make remoting callouts for each value. If however you have more general requirements for calling parameterised methods JS Remoting is worth considering, however you need to ensure you understand its architecture vs tradditional VF pages first.

Visualforce Components. In Visualforce you can wrap parameterised controller logic in components, exposing the parameters as 'attributes' on the component and single get method binding to invoke the method. Your formatting use case is good fit IMHO. Take a look at the following example of a custom output text component referenced in this answer How to call parametrized function from Visualforce?

<c:myOutputText myValue="test"/>
<c:myOutputText myValue="{!MyObject__c.MyFieldToFormat__c}"/>

<apex:component controller="MyOutputTextController">
  <apex:attribute name="myValue" type="String" description="Value to format" assignTo="{!myValueAttr}"/>
  <apex:outputText value="{!formattedValue}"/>
</apex:component>

You can do this with remoting or by setting page properties that you reference in your function.

So instead of:

public string getFormatMe(string a) {
    // do manipulation here
    return a;
}

you could do:

@remoteAction
public static String getFormatMe(String a) {
    // do manipulation here
    return a;
}

<apex:actionFunction action="{!getFormatMe}" name="getFormatMe">
    <apex:param name="a" value="{!a}" />
</apex:actionFunction>

or:

public String a { get; set; }
public String getFormatMe(String a) {
    // do manipulation here
    return a;
}

<apex:inputField value="{!a}" />
<!-- <apex:whatever action="{!getFormatMe}" /> -->

You can pass parameters into your apex:actionFunction directly, and access them through ApexPages.currentPage().getParameters().get('value'), as illustrated below:

<apex:page controller="myController">
    <apex:form >
        <apex:actionFunction action="{!transform}" name="transformer" reRender="newvalue">
            <apex:param name="source" value=""/>
        </apex:actionFunction>

        <apex:pageBlock >
            <apex:pageBlockSection >
                <input type="text" onchange="transformer(this.value)"/>
                <apex:outputText value="{!newvalue}" id="newvalue"/>
            </apex:pageBlockSection>
        </apex:pageBlock>
    </apex:form>
</apex:page>

public with sharing class myController {

    public void transform() {
        string source = apexpages.currentpage().getparameters().get('source');
        // Do something with source here.
        newvalue = source;
    }

    public String newvalue { get; set; }
}

This particular design has several benefits:

  • You get full access to your view state, the method is not static.
  • You keep parameters and unnecessary data out of your view state.
  • You reduce your view state size by not requiring apex:input* or apex:select* elements.
  • A custom component is not required.
  • You can serialize the data in JSON and parse it server-side for complex or non-string objects.

This is perhaps the least commonly known usage of apex:actionFunction, and hasn't been mentioned up to this point, so I've included it here for completeness.

Updated: I just realized that you can't directly return a value through this function, so you'd still need a place to store the result. That being said, the resultant output could be stored to the view state directly, since you have full access to the view state.

Tags:

Visualforce