0

I have an outputPanel containing javascript to change formatting conditionally based on variables in Apex. This is called onComplete from the save button for the page. The custom save function is in an actionFunction that rerenders jspanel. The intent of onComplete is to remove the formatting that highlights changed fields on the page in red when the page successfully saves, but to leave it if there was an error. The variables "hasError" and "errorString" are both set in Apex. The Apex has been thoroughly tested.

<apex:outputPanel id="jspanel">
            {!errorString} {!counter}
            <script>
                function onControllerReturn(){
                    if(!{!hasError}){
                        var x = document.querySelectorAll(".has-changed");
                        var i;
                        for (i = 0; i < x.length; i++) {
                            x[i].classList.remove('has-changed');
                        }
                        console.log('Removed red borders');
                    }
                    console.log('Has Error Test?', {!hasError});
                    console.log('Error String Test', '{!errorString}');
                }
            </script>
</apex:outputPanel>
<apex:actionFunction name="doControllerSave" action="{!justSave}"
                                 rerender="{!$Component.jspanel},...(other components)" />
 <apex:commandButton onclick="doControllerSave();"
  oncomplete="setTimeout(onControllerReturn,1000);" value="Save" styleClass="slds-button slds-button_brand"/>

And the Apex:

public void justSave(){
    try
    {
            //saveEvents is true on success
            hasError = !saveEvents();
            if(hasError){
                errorString = 'ERROR';
                return;
            }

        update target;
        upsert request;
        upsert opportunity;

    }
    catch(DmlException dmlE)
    {
        ApexPages.addMessages(dmlE);
        return;
    }
    return;
}

The Apex code, including saveEvents is confirmed to be working from debug logs. The problem is this: sometimes, the outputPanel with onControllerReturn code does not rerender with the new value of hasError before it is run. Othertimes it does. It almost always works the first time: make a change, click the button, correct result. However, if additional changes to the page are made changing the error condition (a field is blank or not), and the button is clicked again, it returns the previous result some of the time.

I based my code on this: http://blog.jeffdouglas.com/2011/01/17/passing-values-to-javascript-from-apex-controller-method/

1
  • Have you tried using a standard action expression (`action="{! justSave }") on the button, rather than the JavaScript action function? This looks to me like a race condition between the action function and the oncomplete handler, which is waiting for completion of the action its button doesn't have.
    – David Reed
    Commented Dec 31, 2017 at 0:33

1 Answer 1

1

Because your apex:commandbutton doesn't have a rerender attribute on it (which causes the async behavior) and you're also not doing a return false after the onclick call to the actionfunction, the commandbutton will execute a form post when it is clicked and so will the actionfunction.

You can likely achieve what you're looking for without an actionfunction in the page at all and consolidating the logic directly onto the commandbutton.

Your commandbutton markup would look like this:

 <apex:commandButton value="Save"
    action="{!justSave}"
    oncomplete="setTimeout(onControllerReturn,1000);" 
    rerender="{!$Component.jspanel},...(other components)"
    styleClass="slds-button slds-button_brand"/>

You probably also don't need the 1 second delay in the oncomplete but maybe there's some other reason you need it delayed.

0

You must log in to answer this question.

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