Avoiding Race Conditions

Avoiding Race Conditions

An action function provides a way to submit a form programmatically via a JavaScript function call. When an action function is executed from a JavaScript event handler, the default browser behavior continues once the event handler has completed. If the event handler is attached to a Visualforce component that submits the form, an onclick handler for an <apex:commandLink /> or <apex:commandButton /> component, for example, the default browser behavior is to continue with the form submission. This results in a race condition as to which form submission request will be processed first by the server and will often produce unexpected results.

In this Example, we will create a Visualforce page to execute a search for accounts matching a user-entered string of characters. When the user clicks on the button to start the search, a JavaScript function is invoked that checks the number of characters entered. If two or more characters have been entered, the search is executed via an action function. If fewer than two characters have been entered, any existing results are cleared and the search is not executed. In either case, the default form submission from the button is stopped.

/*******************************************************************
* Custom controller for the "Avoiding Race Conditions" recipe.
* Executes a search for accounts matching user-entered text
*******************************************************************/
public with sharing class ActionFunctionSearchController {
    // the search results
    public List results {get; set;}    
    // the search text entered by the user
    public String searchStr {get; set;}    
    // constructor
    public ActionFunctionSearchController() {
        results=new List();
    }    
    // executes the search
    public PageReference doSearch() {
        String wcStr='%'+searchStr+'%';
        results=[select id, Name, Type, Industry from Account where Name like :wcStr];       
        return null;
    }   
    // action method to clear down the list of results
    public PageReference clearResults() {
        results.clear();        
        return null;
    }    
    // getter to indicate if there are results available
    public Boolean getResultsAvailable() {
        return (results.size()&gt;0);
    }
}
<apex:page controller=”ActionFunctionSearchController”>
    <apex:sectionHeader title=”Account Search”/>
    <apex:form id=”frm”> 
        <apex:actionFunction name=”doSearchJS” action=”{!doSearch}” /> 
        <apex:actionFunction name=”clearResultsJS” action=”{!clearResults}” />
        <apex:pageBlock title=”Criteria” id=”crit_pb”>
            <apex:pageBlockSection id=”crit_pbs”>
                <apex:outputLabel value=”Search for” />
                <apex:inputText id=”crit_str” value=”{!searchStr}” />
                <apex:commandButton value=”Go” onclick=”runSearch(); return false;” />
                <apex:outputText style=”font-style: italic”>Enter at least two characters</apex:outputText> 
            </apex:pageBlockSection>
        </apex:pageBlock>
        <apex:pageBlock title=”Results” id=”results”>
            <apex:pageBlockTable value=”{!results}” var=”acc” rendered=”{!resultsAvailable}”>
                <apex:column value=”{!acc.Name}” /> <apex:column value=”{!acc.Type}” />
                <apex:column value=”{!acc.Industry}” />
            </apex:pageBlockTable>
            <apex:outputPanel rendered=”{!NOT(resultsAvailable)}”>
                <h2>No results available</h2>
            </apex:outputPanel>
        </apex:pageBlock>
    </apex:form>

    <script>
        /* JavaScript function to execute a search as long as there are enough characters entered */ 
        function runSearch() { 
            // don’t run the search unless there are enough characters 
            var str = document.getElementById(‘{!$Component.frm.crit_pb.crit_pbs.crit_str}’).value;
            if (str.length>=2)
            {
                /* execute the action function to execute the search in the controller */
                doSearchJS();
            }
            else
            {
                /* not enough characters – alert the user and execute the action function to function execute the action method in the controller to clear the search */
                alert(‘Please enter at least two characters’);
                clearResultsJS();
            }
        }
    </script>
</apex:page>

How it works…

Accountsearch

The Go button defines an onclick handler that executes a JavaScript function to determine the number of characters entered and execute a search or clear the results.

function runSearch() { 
    // don't run the search unless there are enough characters
    var str = document.getElementById( '{!$Component.frm.crit_pb.crit_pbs.crit_str}').value;
    if (str.length&gt;=2) { 
        doSearchJS();
    }
    else {
        alert('Please enter at least two characters');
        clearResultsJS();
    }
}

The onclick handler returns false once the function has completed; this instructs the browser to stop handling the click event at that point, rather than continuing with the default behavior of submitting the form.

ImageReference: http://www.webstepbook.com/supplements-2ed/slides/chapter08-javascript.shtml

Popular Salesforce Blogs