[SalesForce] Calling Apex Class from Custom Button, And Then Refreshing List View

I have added a Custom Button to the List View of the Custom Object. What is the best practice of calling an Apex Class on click of the Custom Button, and refresh the List View after execution of the Apex Class?

So far, I have used an internal Web Service to call the Apex Class. Then using setTimeout function, I have refreshed the List View on return of control from the Apex Class.

Should I have used internal Web Service? Or is that a bad practice? Should I write a Custom VF page instead?

function get(name) { 
    if (name = (new RegExp('[?&]' + encodeURIComponent(name) + 
        '=([^&]*)')).exec(location.search)) { 
        return decodeURIComponent(name[1]); 
    } 
}

{!REQUIRESCRIPT("/soap/ajax/10.0/connection.js")} 
{!REQUIRESCRIPT("/soap/ajax/10.0/apex.js")} 
setTimeout(function() { 
    sforce.apex.execute("ClassName", "functionName", 
    { 
        paramId0 : paramIds[0], 
        paramId1 : paramIds[1] 
    }); 
    ListViewport.instances[get('fcf')].refreshList(); 
}, 0);

Best Answer

JavaScript Custom Buttons. I have not been using JavaScript Custom Buttons for a while now, not only are they slower to respond in some cases, for reasons I've never really got to the bottom of. But they force us to expose global / web service classes for code that would otherwise be internal to our solutions.

Visualforce / Apex Custom Buttons. As you've considered in your question, using a Visualforce Page is another, much more direct and modern option in my view. It has now been available for sometime as an alternative, giving you a 100% Apex native solution without having to expose anything via Web Services.

By using the action attribute on the apex:page element you can invoke some Apex controller logic when your page is loaded by the button. Then return the PageReference you want to redirect the user to. Create a page as follows and then when creating the Custom Button select the List Button type and Visualforce option to select the desired page (note the use recordSetVar to denote a List View page).

<apex:page standardController="Test__c" extensions="ListViewActionController"
   recordSetVar="TestRecords" action="{!doSomething}"/>

The following action controller method performs the neccessary work and redirects back to the list view.

public with sharing class ListViewActionController {

    public ListViewActionController(ApexPages.StandardSetController stdController) { }

    public PageReference doSomething()
    {
        // Do something...
        insert new Test__c();

        // Invoke the list action to return back to the ListView
        return new ApexPages.Action('{!list}').invoke();
    }
}

Salesforce Security Review. Keep the following in mind, if your building a managed package and planning on taking it through this process. Action methods invoked on page load that perform database modifications, are generally (without further discussion) not accepted. Instead you need to modify your page to provide a button the user has to press.

<apex:page standardController="Test__c" extensions="ListViewActionController" recordSetVar="TestRecords">
    <apex:form >
        <apex:pageMessage summary="Click 'Do Something' to confirm." severity="Info" strength="2"/>
        <apex:commandButton value="Do Something" action="{!doSomething}"/>
        <apex:commandButton value="Back" action="{!list}"/>
    </apex:form>
</apex:page>

Image

Hope this helps, enjoy!

Related Topic