15

I have the following command link:

<apex:commandLink value="Edit" action="{!URLFOR($Action.Contact.Edit, rec.id)} />

Which works fine. But I'm trying to make the code generic, to work with multiple objects (not just Contact), so I'd like to specify the action from my controller. Based on the docs for ApexPages.Action, I tried the following:

<apex:commandLink value="Edit" action="{!URLFOR(RecordEditAction, rec.id)} />

With this in the controller:

public ApexPages.Action getRecordEditAction() {
    return new ApexPages.Action('{!$Action.Contact.Edit}');
}

As a test, planning to compute the actual string in the final code. But the test above gives me an "Incorrect argument type for function URLFOR()" error when trying to save the VF page. Looks like ApexPages.Actions are intended to be passed directly as an action param, that is, not via URLFOR, but then there's no way to specify to which object id to apply the action.

How can I specify the desired action from Apex? I don't want to use an url hack (e.g., 003/e); other uses may include delete actions, etc.

2 Answers 2

6

Per Dynamic References to Action Methods Using $Action in the VF Developers Guide:

The $Action global variable allows you to dynamically reference valid actions on an object type, or on a specific record. The most likely way to make use of this is to create a URL to perform that action. For example, you can use the expression {!URLFOR($Action[objectName].New)} in an <apex:outputLink>, with a controller method getObjectName() that provides the name of the sObject.

2
  • 4
    This is what I need. I added an ObjectName property to my controller, and use URLFOR($Action[ObjectName].edit, ...) in my VF Page. Trial and error shows that $Action[ObjectName][ActionName] also works (given a valid ActionName prop value). Commented Jan 22, 2014 at 14:15
  • Your link no longer takes you to the correct documentation. This is why it's best practices to always include the actual text in the answer.
    – NSjonas
    Commented Jun 9, 2020 at 17:39
6

I don't have a full solution for you but this is one way in which you could get the action for Edit at least:

Controller

private Map<String, PageReference> objectEditActions = new Map<String, PageReference>();

public PageReference GetEditAction()
{
    if(isAccount)
    {
        if(objectEditActions.Get('Account') != null)
        {
            return objectEditActions.Get('Account');
        }

        // presumably you're working with a record since you want to edit it
        Account a = [select Id from Account limit 1];
        PageReference pr = (new ApexPages.StandardController(a)).Edit();
        objectEditActions.Put('Account', pr);
        return pr;
    }
    else if(isContact)
    {
        // same deal
    }
}

Page

<apex:commandLink action="{!GetEditAction}" value="Edit"/>

For a new record I think you'd be limited to using a URL hack or having multiple links in the page that are conditionally rendered based on the object being dealt with. For delete the best bet is to just write a delete action in your controller as it doesn't need an interface like edit does.

2
  • This may be useful, although in my case I'm displaying links for each record in a list, so I dislike creating a StandardController instance for each record just to get a page ref; additionally, without URLFOR, I can't control other params, such as retUrl. What we really need is an apex version of URLFOR(), but i'd settle for a way to produce $action.<etc> values from apex code. Commented Jan 22, 2014 at 0:09
  • Does your list contain different types of objects, or by generic do you mean the page should be usable with different lists where each item is of the same type? With the could above you can just cache the PageReference to avoid creating multiple controller instances.
    – Matt Lacey
    Commented Jan 22, 2014 at 0:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .