7

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!

3
  • have you thought about remoteaction : salesforce.com/us/developer/docs/apexcode/Content/…? You can get the callback status using remote action.
    – unidha
    Apr 27, 2015 at 7:45
  • Good thought - I did try using a remote action but the issue is its static within the context of the request. Therefore my dataSaved property would return null if I made it static.
    – Jim
    Apr 27, 2015 at 23:17
  • Had another idea - take a look at the bottom of my answer. Apr 27, 2015 at 23:57

2 Answers 2

3

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.

3
  • Thanks for the answer - I did try something similar, but I got frustrated due to the delay in time to rerender the script panel, which was required each time a field was changed. As this works and I didn't state this perf requirement upfront I will accept this as the answer if there is no suggestions by eod :) Thanks
    – Jim
    Apr 27, 2015 at 23:20
  • Thanks for the update - this meant that at the time when I clicked the button "Do Stuff" I would still need to rerender the JS to get the updated dataSaved property. While much faster there was still a delay while the block re-rendered. I ended up taking a purely js approach - see my answer below.
    – Jim
    Apr 28, 2015 at 1:00
  • Well, you could avoid a rerender if you wrote to a javascript global variable or a part of the dom (ie a hidden input field) that you had designated for this function. Then you could refer to this value in the confirmProceed() function. So I'd see it as RemoteAction->Save Result in Var or DOM->Update Controller. So as soon as you have that result saved, you can use in in confirmProceed Apr 28, 2015 at 1:12
1

I ended up removing the dependency on the controller to track the record state. Instead I had a hidden input field on the VF page and rewrote the value of this field with JS. I created two new JS functions - one to populate the hidden field with false when a field was changed & another to populate it with true when the record was saved. In the confirmProceed() function I used getElementById() to grab the value of the field and check it, then displayed the appropriate prompt to the user. This removed the requirement to rerender part of the VF to get the updated value from the controller.

This approach allowed me to return a boolean value to the command button "Do Stuff" which then prevented or allowed the action method from running depending on the user input in the JS confirm.

You must log in to answer this question.

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