Login


Prevent User Navigating Away from Page with Unsaved Changes

By Jonathan Wood on 8/6/2011
Language: JavaScript
Technology: ASP.NETjQuery
Platform: Windows
License: CPOL
Views: 23,812
Web Development » Client Scripting » General » Prevent User Navigating Away from Page with Unsaved Changes

Screenshot of Demo Project

Download Demo Project Download Demo Project

Introduction

When a user edits data in a desktop application such as a word processor, and then closes the application without saving that data, most applications will warn the user that they have unsaved changes and provide options for saving the data or to continue editing.

This is a little trickier with web applications because it is really the browser that is in control. However, with a bit of client-side scripting, you can prevent the user from unexpectedly losing their changes.

onbeforeunload

The onbeforeunload event fires prior to a document being unloaded. This event fires in cases such as the user clicking a link to another page or entering a new URL in the address bar. And it even fires if the user attempts to close the browser. So this is the perfect event for warning a user if they have unsaved changes.

If the onbeforeunload handler returns a string, a dialog prompts the user to confirm they really want to navigate away and gives them the option of staying on the current page. The exact appearance of the dialog will depend on the browser. The one in the image above is from Internet Explorer 9.

The dialog can also include a custom message. Note that there are some limitations on the text that appears in the dialog. For example, you cannot change the text in the title bar. This is primarily a security feature to prevent malicious websites from making it appear to the user that a system message box is being displayed.

Of course, even with browsers becoming much more focused these days on complying with web standards, I did find one bug with Internet Explorer when the user is navigating away via JavaScript, such as in the following example.

<span onclick="window.location='http://www.blackbeltcoder.com'">Click Me</span>

When the user clicks a link like this, and the unbeforeload handler displays a dialog box, and the user selects the option to stay on the current page, then my testing on Internet Explorer 9 indicates the dialog box will appear a second time. And if the user selects the option to stay on the current page the second, the debugger throws up the error Microsoft JScript runtime error: Unspecified error. The same markup works just fine on all the other browsers I tested.

I was quite surprised by this error. I was thinking the days of Internet Explorer quirks were behind us. In my case, the error wasn't critical. I just made sure that any links on the page were regular anchor tags, and it works fine.

Prompting Only When Edits Have Been Made

The next step is to limit the appearance of the prompt to only when the user has made a change on the current page. It would be rather silly to display the dialog box described above if they haven't. jQuery provides the change method, which calls the handler when an element is changed. So we can use this handler to enable our onbeforeunload handler.

However, it can be rather tedious to hook up this handler for every editable control on the current page, especially if you plan to use this code on many pages. Fortunately, jQuery makes this very easy. We can just use the selector $(input:not(:button,:submit),textarea,select) to refer to all <input> elements that are not type button or submit, as well as all <textarea> and <select> elements. Not only does this cover all the standard edit controls, but it will also include the new edit elements avaiable with HTML 5, which are implemented as new <input> types.

Don't Prompt on Submit

We've just about covered all the logic required, but there's one more thing: When the user tries to actually submit the page, this will cause the page to unload and our prompt will appear. We definitely don't want that, so we'll add a click handler for any <input> elements of type submit, and this handler will disable our code that displays the prompt. The final jQuery is shown in Listing 1.

Again, I used a generic selector to refer to all submit buttons on the current page. This eliminates the need to hook up these handlers to specific elements. However, if you need finer control over this logic, you will need to tweak the code and hookup events only for those elements appropriate for your specific case.

Listing 1: jQuery Script to Warn User When Navigating Away with Unsaved Changes

var warnMessage = "You have unsaved changes on this page!";

$(document).ready(function() {
    $('input:not(:button,:submit),textarea,select').change(function () {
        window.onbeforeunload = function () {
            if (warnMessage != null) return warnMessage;
        }
    });
    $('input:submit').click(function(e) {
        warnMessage = null;
    });
});

Note the click handler. It simply sets the warnMessage variable to null. In the onbeforeunload handler, the text is only returned if warnMessage is not null. This effectively disables the prompt when a submit button has been clicked.

Conclusion

The attached download contains my test project, which demonstrates all the code described in this article.

It's very easy for a user to enter data and not realize it has not been saved. In many cases, it is better not to mess with the user's navigation--it can become extremely annoying. However, when the user is at risk of losing data they've entered, it can make good sense.

End-User License

Use of this article and any related source code or other files is governed by the terms and conditions of The Code Project Open License.

Author Information

Jonathan Wood

I'm a software and website developer working out of the greater Salt Lake City area of Utah. I've developed many websites including Black Belt Coder, Trail Calendar, and others.

I hike each week with my dogs Suki and Sasha. You can see my hiking blog at Hiking Salt Lake.