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/

  • 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 Dec 31 '17 at 0:33
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.

  • Will give that a shot- question though: what does the 'return false' do in the onclick Javascript? Prevent a form post (not clear on what that is, either). – LucidLunatic Dec 31 '17 at 2:54
  • 1
    Step 1. Just changed the onClick to include return false as the final line in the on click call. This did not fix it. Step 2. Added the rerender to the button as well. Did not do the trick. Step 3. Switched to using action and justSave directly. Worked. Many thanks. – LucidLunatic Dec 31 '17 at 5:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.