[SalesForce] Return Boolean From Action Function called from JS

I have a page which displays a bunch of input fields for a record (fairly standard) and allows the user to update those fields and then save the record. On the bottom of the page there is a command button within a component that does some checks on some related data and redirects the user accordingly. What I need to do is find whether the current record has been saved and if it hasn't display a simple JS alert.

In the component I have a command button like below (Note – need immediate as this does not require the parent page to be validated):

<apex:commandbutton value="Do Stuff" onclick="ProceedJS();" immediate="true" action="{!DoPageRedirect}" /> 

On the page which the component is contained in I have the following action function – I perform the rerender on the pageState outputText as I need the latest value for the dataSaved property:

<apex:actionFunction name="ProceedJS" reRender="pageState" oncomplete="return confirmProceed();" /> 
<apex:outputText value="{!dataSaved}" id="pageState" /> 

The javascript function confirmProceed looks like this:

function confirmProceed() 
        {
            var dataSaved = document.getElementById('myPage:myForm:myBlock:pageState').innerHTML ;
            alert('Action function complete....Data saved var: ' + dataSaved);  
            if(dataSaved == 'false') {

                if(confirm('Are you sure you wish to continue - any unsaved changes will be lost.')) {

                }
                else { return false; }
            }
        }

I currently manage the dataSaved on the controller (this is working as expected) as a boolean. When the record is saved I set it to true in the apex save method which is called by the save button and when the field changes it is set to false by calling an action function on the onchange event of the fields on my page.

I have tried the below:

<apex:commandbutton value="Do Stuff" onclick="return confirmProceed();" immediate="true" action="{!DoPageRedirect}"/> 

Which is close to what I need, but the reRender must be performed on the outputText pageState to get the latest value for dataSaved. Therefore I am calling the actionFunction.

Has anyone seen a better way of doing this? I really feel like I am missing something.

Otherwise is it possible to have the action function return a bool back to the on click of the command button "Do Stuff"? So that it works in a similar fashion to just going return confirmProceed() on the "Do Stuff" command button? But with the rerender to get the updated value of dataSaved?

Any help appreciated!

Best Answer

You could wrap a script in an outputPanel and rerender it on every save. Then you'd have the most up-to-date value of the variable. eg:

<apex:outputPanel id="saveResultScript">
    <script>
    function confirmProceed (){
        var dataSaved = "{!JSENCODE(dataSaved)}";
        if(dataSaved == 'false' && !isDirty) {
            if(confirm('Are you sure you wish to continue - any unsaved changes will be lost.')) {
            }
        }else {
            return false;
        }
    }
    </script>
    </apex:outputText>
</apex:outputPanel>

Outside this block we have another script tag which we'll put the isDirty variable (so it doesn't get rerendered on save)

<script>
var isDirty = false;
</script>

As long as this entire panel is rerendered on every save, we can check the newly updated dataSaved variable and the locally updated isDirty variable (you said you had a variable that performs this function on any onenter event)

This way, we don't need to talk to the controller for confirmProceed to work. Hopefully this helps a little. I feel a little unsure of your requirements, but this is something that I have done several times myself and it works pretty well.

Oh and using a RemoteAction as suggested in the comments would probably work too, as long as you keep in mind that RemoteAction methods need to be static. They definitely return a value immediately for you to act on.

Update One last thought - you could use a RemoteAction to save your data and then (depending on the result) call an actionFunction to update the dataSaved var on the controller non-statically - while you can do what you want without waiting for a rerender - this should be very performant.

Related Topic