Is there any way to pass constants from an apex:page so that the controller method invoked via its action attribute can be configured?

I’ve started work on implementing Visualforce pages to use in list view buttons using the approach How to convert mass actions on list view records from Classic to Lightning Experience?. We have many of these buttons, and they have lots in common to such an extent that there are just two constants that need to change from button to button. So while I need to create many pages, most of the rest of the code can be common.

The first approach was to do most of the work in a common component so each page could set the appropriate constants:

<apex:page
        standardController="MyObject__c"
        extensions="MyController"
        recordSetVar="unused"
        >
    <c:ListActions
            ...
            operation="MyObjectActions.move"
            value='last'
            ...
            />
</apex:page>

and that works fine for cases where the page is displayed.

But now for some cases, I’d like to not render the page. That can be done via the apex:page action attribute, once the work is done, returning the StandardSetController cancel() PageReference to go back to the list view page:

<apex:page
        standardController="MyObject__c"
        extensions="MyController"
        recordSetVar="unused"
        action="{! init }"
        >
</apex:page>

My problem is how to inject the two constants for this case. About the only attribute of apex:page that perhaps I could abuse is the extensions, but I’d have to create multiple marker classes. Or I could add many methods to the controller that set the required permutations of the constants. Or is there a better way to go?

PS

It isn’t elegant but I guess I can live with:

<apex:page
        standardController="MyObject__c"
        extensions="MyController"
        recordSetVar="unused"
        action="{! execute_BenefitActions_move_last }"
        >

and:

public PageReference execute_BenefitActions_move_first() {
    return execute('BenefitActions.move', 'first');
}
public PageReference execute_BenefitActions_move_up() {
    return execute('BenefitActions.move', 'up');
}
public PageReference execute_BenefitActions_move_down() {
    return execute('BenefitActions.move', 'down');
}
public PageReference execute_BenefitActions_move_last() {
    return execute('BenefitActions.move', 'last');
}

...

private PageReference execute(String operation, String value) {
    this.operation = operation;
    this.value = value;
    ...

But before I add this ugliness, if you have a better approach, please share.

PPS

Query string parameters can’t be used in this case – see Is a “Content Source” of “Visualforce Page” required for Ids for the checked list view items to be received by a StandardSetController?

Answer

The best route I can think of – and I tried this out in a sandbox; it works – is introspecting off the Visualforce page’s name itself, embedding the parameters therein via some delimiter.

While it’s neither beautiful nor elegant, it does streamline the controller somewhat (no extra action methods) and allows the use of a single page per sObject, saved an arbitrary number of times under different names.

Visualforce Page TestPage_param_param2.vfp

<apex:page standardController="Account"
           extensions="TestController"
           recordSetVar="unused"
           action="{! runAction }">
</apex:page>

Controller TestController.apxc

public class TestController {
    private ApexPages.StandardSetController c;

    public TestController(ApexPages.StandardSetController c) {
        this.c = c;    
    }

    public PageReference runAction() {
        List<String> parameters = ApexPages.currentPage().getURL().substringAfterLast('/').substringBefore('?').split('_');

        System.assertEquals(3, parameters.size());
        String operation = parameters[1];
        String value = parameters[2];

        System.debug(String.format('Performing operation {0} with value {1} on selected records {2}', 
                                   new List<String> { operation, value, String.join(c.getSelected(), ', ') }));

        return c.cancel();
    }
}

Result

When run from a list view, this yields

16:32:07:113 USER_DEBUG [15]|DEBUG|Performing operation param with value param2 on selected records [Account (Id:0013600001sxEUmAAM, RecordTypeId:01236000000STbiAAG)]

Attribution
Source : Link , Question Author : Keith C , Answer Author : David Reed

Leave a Comment