To read the article online, visit http://www.4GuysFromRolla.com/webtech/100604-1.shtml

Prompting a User to Save When Leaving a Page

By Scott Mitchell


After Reading This Article...
After reading this article, check out Using ASP.NET to Prompt a User to Save When Leaving a Page, which shows how to extend the Page class to provide this functionality in an ASP.NET Web page through a simple set of server-side methods. Using ASP.NET to Prompt a User to Save When Leaving a Page builds upon the knowledge from this article, making the process blindingly simple to accomplish with ASP.NET.

Introduction
As a user, is there anything more frustrating than spending several minutes entering or changing data into a form, only to have it not be saved for one reason or another? It's annoying when it's the software's fault - such as the database server being down - and embarrassing when it's your own fault - such as closing the window before clicking the "Save" button, or clicking on a link on the page and being whisked away to some other page prior to saving the changes. Recently I was working on a project for a client that essentially moved a company's data collection from a paper-based office to an electronic-based office. Namely, the standard pages of information employees were once required to fill out, were replaced with Web pages accessible through the company's intranet.

One common theme that kept resurfacing during the testing of the application was that many of the employees, especially those with limited experience with computers, found themselves going to a page to edit some pre-entered data, making the changes, and then either closing their browser or moving to another page before hitting the "Update" button. As you can guess, doing this didn't save their changes, which led to confusion first, then embarrassment, and finally frustration. (It also didn't help that many of these pages had several dozen input fields, with "Update" buttons only at the top and bottom of the page. So if a user visited a page, scrolled down a bit and made some changes, they'd have to know/remember to scroll back to the top or bottom of the page and click the "Update" button to save the changes.)

To help surmount this problem of leaving a page after making changes, I utilized the onbeforeunload event. This client-side event, which works in Internet Explorer and FireFox version 0.9 and up, is fired prior to the onunload event, which fires when the body is being unloaded (either through the browser being closed or the user navigating to a different URL). Using the onbeforeunload event, you can create an event handler that, if it returns a string, will display a prompt to the user when leaving the page, asking them if they are sure they want to leave the page. Using this technique I was able to present the users with a warning if they attempted to leave the page without saving their data.

In this article we'll look at the onbeforeunload event and how you can use it to provide a similar warning to your users when leaving a page from which they need to save their changes. We'll see two working examples: a naive one, that always displays a confirmation dialog, and a more intelligent one that only displays a confirmation dialog box if the user has, in fact, changed one or more of the form fields on the page. Read on to learn more!

A Simple Approach: Warn the User Whenever They Are Leaving the Page
The simplest and most naive approach is to warn users whenever they are leaving a page, regardless of whether or not they had made any modifications to the form fields on the page. With this approach, whenever a user visits a data entry page, whenever they leave - be it through jumping to another URL or closing the browser window - they'll get a dialog box that informs them that if they made any changes those changes will be lost if they didn't click the "Save" (or "Update") button. To accomplish this, all that you need to do is add the following JavaScript to your page:

<script language="JavaScript">
  window.onbeforeunload = confirmExit;
  function confirmExit()
  {
    return message to display in dialog box;
  }
</script>
[View a Live Demo!]

With the above JavaScript when the user leaves the page - either by clicking on a link, they'll see a dialog box prompting them with a message you specify in the return parameter of the event handler. In the live demo, the event handler returns "You have attempted to leave this page. If you have made any changes to the fields without clicking the Save button, your changes will be lost. Are you sure you want to exit this page?", which results in the dialog box shown at the right.

One downside of this approach is that any action that causes the page to be unloaded - including the submission of a form - will display the dialog box shown above. In the live demo, you might have noticed that when the user clicked the Save button they were given the same dialog box as when they clicked on a hyperlink, or closed their browser. To prevent this, we need to make our onbeforeunload event handler a bit more intelligent. There are a couple of techniques that can be used, the simplest (to me) being the following:

  • Create a global JavaScript variable that serves as a flag, called needToConfirm, with a default value of true.
  • In the onbeforeunload event handler, if this variable has a value of true, then the event handler returns the message to display in the dialog box. If it has a value of false, then the event handler returns nothing, which causes the browser to not display a dialog box, but rather just send the user onto the requested page like normal.
  • Finally, in the submit button's onclick event, we want to set the needToConfirm flag to false.
This technique can be seen in the following code and live demo:

<script language="JavaScript">
  var needToConfirm = true;

  window.onbeforeunload = confirmExit;
  function confirmExit()
  {
    if (needToConfirm)
      return message to display in dialog box;
  }
</script>

...

<input type="Submit" value="Save" onclick="needToConfirm = false;" />
[View a Live Demo!]

Prompting the User Only When Changes Have Been Made
The approach just examined is a bit naive in that it prompts the user if they are certain if they want to leave the page regardless of whether or not any data has been changed on the page. That means that even if the user hits the page to quickly check a few values, does so, and then attempts to close her browser, she'll be shown a dialog box asking her if she's certain she wants to leave the page. This can, no doubt, be annoying for a user. Ideally, a user would only see this dialog box if they went to a page, changes some data entry fields, and then attempted to leave the page without having clicked the Save button.

This can be accomplished without too much trouble. The best approach, in my opinion, is to run a JavaScript function when the page has loaded that saves the values of the data entry controls in an array. In the onbeforeunload event handler, this array is scanned to determine if there are any changes between the current data entry fields and their saved values in the array. If there are any discrepancies, then the event handler returns a string, displaying the confirmation dialog box; otherwise, the event handler returns nothing, allowing the user to leave the page as they'd expect.

In practice, I accomplish this using two arrays. One array that holds the IDs of the data entry form fields, and one array that holds their values. Let's look at the needed client-side script in two pieces. First, let's look at saving the form fields' initial values when the page is loaded.

<script language="JavaScript">
  var ids = new Array('name', 'gender', 'sendEmail', 'radVanilla', 
                                    'radChocolate', 'radStrawberry');
  var values = new Array('', '', '', '', '', '');
  
  function populateArrays()
  {
    // assign the default values to the items in the values array
    for (var i = 0; i < ids.length; i++)
    {
      var elem = document.getElementById(ids[i]);
      if (elem)
        if (elem.type == 'checkbox' || elem.type == 'radio')
          values[i] = elem.checked;
        else
          values[i] = elem.value;
    }      
  }

  ...
</script>

...

<form ...>
  <b>What is your name:</b> <input type="text" id="name" name="name" /><br />
  <b>What is your gender?</b>
  <select id="gender" name="gender">
    <option value="Male">Male</option>
    <option value="Female">Female</option>
  </select><br />
  
  <input type="checkbox" name="sendEmail" id="sendEmail" /> <b>Send me your newsletter!</b>
  <br />
  <b>What is your favorite type of ice cream?</b><br />
  <input type="radio" id="radVanilla" name="iceCream" checked="checked" /> Vanilla<br />
  <input type="radio" id="radChocolate" name="iceCream" /> Chocolate<br />
  <input type="radio" id="radStrawberry" name="iceCream" /> Strawberry<br />
  <p>
  <input type="Submit" value="Save" onclick="needToConfirm = false;" />
</form>

<script language="JavaScript">
  populateArrays();
</script>

Notice that I created two arrays, ids and values. The ids array has six string entries, which correspond to the six data entry form fields in the live demo. The values array will hold a value for each form field, so it is created with six blank string values. Next, in the populateArrays() function, the ids array is looped through and the HTML elements are programmatically referenced via the document.getElementById() function. For radiobuttons and checkboxes, the checked property is saved in the values array; for other form fields (textboxes, drop-down lists, etc.), the value property is saved.

One important thing to note is that the populateArrays() function is called after the form fields have been spelled out. It's important that you call this function so that the form fields' values are saved in the array. It's vital that this call occur after the form fields have been defined, otherwise the function will not succeed in saving the initial values, as it will try to access the form fields before they have been received by the browser.

The second task we are faced with is modifying the onbeforeunload event handler so that it only returns a string if there is a discrepancy between the actual form field values and the initial form field values (which were saved for us in the values array). To accomplish this, I simply loop through the elements in the values array and see if there is a mismatch between it and the actual value. If so, I return the message to display in the dialog box. Otherwise, I continue looping. If no mismatches are found, the event handler simply exits without returning anything, thereby allowing the user to leave the page without an unnecessary dialog box.

<script language="JavaScript">
  var needToConfirm = true;
  
  window.onbeforeunload = confirmExit;
  function confirmExit()
  {
    if (needToConfirm)
    {
      // check to see if any changes to the data entry fields have been made
      for (var i = 0; i < values.length; i++)
      {
        var elem = document.getElementById(ids[i]);
        if (elem)
          if ((elem.type == 'checkbox' || elem.type == 'radio')
                  && values[i] != elem.checked)
            return message to display
          else if (!(elem.type == 'checkbox' || elem.type == 'radio') &&
                  elem.value != values[i])
            return message to display
      }

      // no changes - return nothing      
    }
  }
</script>
[View a Live Demo!]

That's all there is to it! As you can see in the live demo, the dialog box is only displayed if one (or more) of the form fields have changed from the first page visit.

Conclusion... and Moving Forward...
At this point we have examined the onbeforeunload event can be used to display a confirmation dialog box when the user is attempting to leave the page after having made changes to the form fields but before saving the data. There are still a couple of improvements we can make here. First off, if you attempt to use this code in an ASP.NET Web page that has LinkButtons you'll find that when a user clicks a LinkButton they are, as you might expect, asked if they are sure they want to leave the page. If they click OK, however, they are asked again. This has to do with the fact that the LinkButton's href contains some JavaScript, and we'll look at a workaround in a future article.

Another shortcoming is that to apply the more intelligent means of prompting when exiting only if there have been changes, we have to write client-side code that includes a list of all of the IDs of all of the data entry form fields. This can be difficult since the client-side ID of an ASP.NET Web control is dependent on whether or not its inside other controls. (For example, a checkbox with a server-side ID property value of sendEmail that's placed within a DataGrid might have the final client-side ID of DataGridID_ctrl0_sendEmail.) Furthermore, adding this support requires cutting and pasting the necessary JavaScript functions into the page. As we'll see in an upcoming article, all of this can be handled for us behind the scenes, boiled down to one line of code per Web control in the data entry section.

Happy Programming!

  • By Scott Mitchell


  • Article Information
    Article Title: Prompting a User to Save When Leaving a Page
    Article Author: Scott Mitchell
    Published Date: Wednesday, October 06, 2004
    Article URL: http://www.4GuysFromRolla.com/webtech/100604-1.shtml


    Copyright 2014 QuinStreet Inc. All Rights Reserved.
    Legal Notices, Licensing, Permissions, Privacy Policy.
    Advertise | Newsletters | E-mail Offers