6

We need to universally handle changed data on forms in ASP.NET MVC. Our application has ~100 forms, and the user should be prompted if they start editing a form and click on anything other than Save (i.e. something like "Your data has been changed. Click OK to return to the form, or Cancel to lose all changes.").

It looks like SO implements this (while asking a question) using JavaScript. In general, is this the best way? Also, any tips on how best to implement this?

2 Answers 2

5

The way I've done this is to use javascript to store the initial values of inputs when the page loads. Then I have a beforeunload handler that checks to see if any of the inputs have a different value than when the page was loaded. If any inputs are changed, it prompts the user to confirm that they want to leave the page, canceling the action if they cancel. In my submit logic, I set a flag that keeps the beforeunload check from happening so a submit doesn't get the prompt.

I suspect there is a jQuery plugin to do this, but I haven't implemented this since I started using jQuery. My earlier code used Prototype.

Edit: Couldn't find a jQuery plugin, but I could have just missed it. Here's a sample of how I might do it. Obviously, there's more that could be done. Note I wasn't able to get it to work with pure jQuery -- not sure exactly why, the popup would appear twice.

This should work with all input elements. You might want to change it to ignore/handle buttons, though. I only adjusted it to ignore a submit button (so it can post back without the popup). If other button types can cause a page unload, you may need to address that.

var CheckOnClose = function() {
    this.initialize();
}

CheckOnClose.prototype = {
    submitting: false,
    initialize: function() {
        var that = this;
        window.onbeforeunload = function() { return that.checkLeavePage(); }
    },
    isChanged: function() {
        var changed = false;
        $('input:not(:submit)').each( function() {
            var iv = $(this).data('initialValue');
            if ($(this).val() != iv) {
                changed = true;
                return false;
            }
        });
        return changed;
    },
    setSubmitting: function() {
        this.submitting = true;
    },
    checkLeavePage: function() {
        if (!this.submitting && this.isChanged()) {
            return 'You have some unsaved changes.';
        }
    }
}

var checker = new CheckOnClose();

$(document).ready(function() {

    $(':input:not(:submit)').each( function() {
        $(this).data('initialValue',$(this).val() );
    });
    $(':submit').click( function() {
        checker.setSubmitting();
    });
});
Sign up to request clarification or add additional context in comments.

9 Comments

I would suggest that the function that checks before/after values is called from a the onblur event... that way you can easily scale it with jquery ($('.check_changes').blur(func);). In order to make this even easier, at page load time I'd save the initial value into a new property of the element... you can do this via jquery, too.
I should add that if that function determines that the element has changed, then it should modify an isDirty variable at the page scope. Then, when you're deciding whether or not to allow the user to leave, you only have to check this variable.
@jamesshannon -- using jQuery, I'd suggest using the data() method and store the initial value that way.
@LuckyLindy -- my code sample works with all inputs. If your submission uses ajax and makes non-standard use of other controls as inputs, you'll need to adjust the function that records initial values/checks changes.
@jamesshannon -- I tried your blur handler to retrieve changes, but it didn't reliably run when changing an input then clicking a link. I think that the beforeunload event was occurring prior to the blur. I had to change it back to look for changes in the beforeunload handler.
|
1

JavaScript is your only shot for doing this. It doesn't even have to be a complicated bunch of code. All you have to do is have a global variable to flag if the form is in editing stages (var formEdited = false; would do), and then add this snippet to your page:

 window.onbeforeunload = confirmExit;
    function confirmExit()
    {
        if (formEdited)
        {
                return "You have attempted to leave this page.  If you have made any changes to the fields without Submitting the form, your changes will be lost.  Are you sure you want to exit this page?";
         }
          // no changes - return nothing      
    }

1 Comment

Of course jQuery/Prototype/other libraries could be used as well, but the basic implementation is as simple as the above snippet.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.