04 April, 2016

Warning APEX Users of Form Changes on Navigation away from the page.

It has come to my attention the the link back to this article that originally appeared on the Enkitec.com web site is broken. Knowing that people still find this useful, I've copied it here so that it can be easily found and referenced.



It's a common problem. A user spends time entering data into a form and then, for some reason, clicks a button or tab that will navigate away from the form without saving his data. Wouldn't it be nice if there were a way to warn the user that the data hasn't been saved, and that they may lose their work?Well, there actually is a way to do this in JavaScript, and you don't have to do a lot of work yourself. Here's how...

The following JavaScript is the key for Standard APEX Forms. You can include it either in the HTML HEADER of the page, or in an HTML Region on the page:

<script type="text/javascript">

function onChangeinit() {

// This function sets up those fields in <strong>STANDARD APEX FORMS</strong>
// which should trigger the "Are You Sure" Popup box upon
// navigating away from the page.
// First set up the array of elements in the form
// This method uses JavaScript to create an array of elements.

var fields = document.getElementById('wwvFlowForm').elements;

// Now loop through the array and assign the on-change event
// The onchange function sets the value of a JavaScript variable
// to '1' to show that something has changed.

for (var i=0; i<fields.length; i++) {
     $x(fields[i]).onchange = function () {
     window.unsaved=1;
     }
   }
}

// Now Set up the UNSAVED variable
// and the function that checks it on UNLOAD.

window.unsaved = '';
window.onbeforeunload = function() {
    return window.unsaved ? 'There may be unsaved changes to your data.' : undefined;
}
// And you're done.
</script>

For APEX Tabular Forms, the code needs to change just a bit to cover all the iterations of the fields on the page:

<script type="text/javascript">

function onChangeinit() {

// This function sets up those fields for a <strong>TABULAR FORM</strong>
// which should trigger the "Are You Sure" Popup box upon navigating
// away from the page.

// First set up the array of elements in the form
// This method uses JavaScript to create an array of elements.

var fields = document.getElementById('wwvFlowForm').elements;

// Now loop through the array and see if the id matches the format f99_9999
// If it does, assign the on-change event.
//
// The onchange function sets the value of a JavaScript variable
// to '1' to show that something has changed.

for (var i=0; i<fields.length; i++)
    if (fields[i].id.match('^f[0-9]{2}_{1}[0-9]{4}$'))
    {
      $x(fields[i]).onchange = function () {window.unsaved=1;}
    }
}

// Now Set up the UNSAVED variable
// and the function that checks it on UNLOAD.

window.unsaved = '';
window.onbeforeunload = function() {
    return window.unsaved ? 'There may be unsaved changes to your data.' : undefined;
}

// And you're done.
</script>

The onChangeinit JavaScript function needs to be run whenever the page loads. To do that, we call it by placing the following JavaScript in the Execute when Page Loads attribute at the page level.

onChangeinit();

Finally, we want to provide a way to short circuit this for instances where we want them to be able to press a button without getting the message. The most common example of this would be the SAVE button. Again, you can include it either in the HTML HEADER of the page, or in an HTML Region on the page.

<script type="text/javascript">
function preSubmit() {
    // Call this before any action where you want the user
    // to be able to navigate without the warning message.
    // For instance, add this to the BUTTON ATTRIBUTES of the
    // SAVE button of your form.

    window.unsaved='';
}
</script>

The last thing to do is edit any buttons that we want to be able to submit the page without being warned and make sure they call the preSubmit JavaScript function.

To make this change to SUBMIT buttons, edit the button and do the following:

• In the Action When Button Pressed region, change the Action to Redirect to URL
• in the URL Target enter the following:

javascript:preSubmit();apex.submit('<>');

Make sure the that <> in the code above is actually the name of the button that you’re editing. That way when the apex.submit JavaScript function is called, it will be as if the user pressed the button.

For the DELETE buttons, edit the button and do the following:

• In the Action When Button Pressed region, change the Action to Redirect to URL
• in the URL Target enter the following:

javascript:preSubmit();apex.confirm(htmldb_delete_message,'<>');

Again, make sure the that <> in the code above is actually the name of the button that you’re editing.

That's it. That's all there is to it. The nice thing about this is that it will even catch changes made by other JavaScript.

2 comments:

Graham Whiteman said...

This is awesome!!.

The only negative side affect I have is when navigating away via
the tabs across the top the warning message pops up twice. Any idea why this function would be being called twice in this scenario?

Doug Gault said...

Hmm.. Not sure about this. I'd try to use the Javascript debugger in your browser to see what's going on.

If you're using APEX 5.0+ then this trick isn't really necessary any more as 5.X automatically checks to see if you're navigating away before saving changes.