1

I am working on ASP.NET 3.5 website project and using jQuery to warn users if they modified a page and attempt to leave the page without saving, so doing something like this:

var warning = "Please save changes you made.";
var isDirty = false;

$(document).ready(function()
{

      $('input:text,input:checkbox,input:radio').bind('change', function()
      {

            isDirty = true;

            $('input[type=submit]').bind('click', function(e)
            {

                isDirty = false;
            });

            window.onbeforeunload = function()
            {

                if (isDirty)
                {

                    return warning;
                }
            }
        });
    });

It works fine, but when I make changes on a page and then select a different item in a dropdown on a page, which causes a post back, I get a warning, which I should not.Is it feasible to implement this feature in jQuery, i.e. give warning on really leaving page, but ignoring postbacks, and what changes to the script I need to make in that case?

Ok, I modified script slightly, created a hidden field to save dirty state between postbacks, so it looks like this:

 var warn_on_unload = "Leaving this page will cause any unsaved data to be lost.";
 var previouslyDirty = false;
 var isDirty = false;

 $(window).load(function()
 {

    previouslyDirty = $('#dirtyFlag').val() == '1';

 });

 $(window).unload(function()
 {

        $('#dirtyFlag').val(previouslyDirty ? '1' : '0');
 });

 $(document).ready(function()
 {

        $('input:checkbox,input:radio').one('change', function()
        {

            isDirty = true;

            previouslyDirty = true;

        });



        $('input:text, textarea').keydown(function()

        {

            isDirty = true;

            previouslyDirty = true;

        });

        $('form').submit(function(e)
        {

            isDirty = false;

            previouslyDirty = false;

        });

        $('select').bind('change', function(e)
        {

            isDirty = false;

            previouslyDirty = true;

        });

        window.onbeforeunload = function()
        {

            if (isDirty || previouslyDirty)
            {

                return warn_on_unload;

            }
        }

    });

Still behaves incorrectly after non-submitting postbacks, which it should allow them without a warning, but saving dirty state, so if I change dropdown, no problem on postback , but if I try to leave page after that, should get a warning. Also, need to take of care of submitting postbacks, i.e. saving buttons, obviously allowing them and clearing all dirty flags previously set.

Victor
  • 297
  • 1
  • 5
  • 19
  • I may be dumb, but what actually does that mentioned dropdown do? – Adam Kiss Feb 06 '10 at 19:00
  • @Adam. That particular dropdown changes foreign key value. But this is a broader issue, as I have various non-submitting buttons, dropdowns, wizard buttons, etc. that cause a postback, and I can't have warning on any of them, only when users leave page for good. – Victor Feb 06 '10 at 19:54
  • Well, that does not go as special "Answer", more like idea: navigating to other site or closing a page must have different "code" then changing a value of something, so although both call unload, there must be something different... check with firebug maybe? – Adam Kiss Feb 06 '10 at 23:12

3 Answers3

2

Since we already have jQuery, we use it to detect whether the form has changed as show in the accepted answer to this question What is the easiest way to detect if at least one field has been changed on an HTML form?

Additionally, we know that webforms pages only have a single form. Webforms calls form.onsubmit() and form.submit() when handling a postback via a link.

To track the original serialized value across AutoPostBack events, store the serialized form data in a hidden field.

<asp:HiddenField id="serializedForm" runat="server" />

$(document).ready(function(){

    var theform = $('form');
    var serialized = theform.serialize();
    var previous = null;

    // track original serialized across postbacks
    var hidden = $('#<%# serializedForm.ClientID %>');
    if ('' == hidden.val()) {
        serialized = hidden.val();
    } else {
        hidden.val( serialized );
    }

    window.onbeforeunload = function(e) {
        if (serialized != theform.serialize()) {
            return "Are you sure you want to leave the page without saving?";
        }
    }

    // postback -> __doPostBack -> form.onsubmit -> here
    theform.submit(function(){
        // keep in case of validation fail
        previous = serialized;

        // prevent the onbeforeunload prompt
        serialized = theform.serialize();
    });

    // there might be ASP.NET validators
    if (typeof(ValidatorOnSubmit) == "function") {
        var asp_ValidatorOnSubmit = ValidatorOnSubmit;
        ValidatorOnSubmit = function() {
            var result = asp_ValidatorOnSubmit.apply( arguments );
            if (!result) {
                serialized = previous;
            }
            return result;
        }
    }

});
Community
  • 1
  • 1
Lachlan Roche
  • 25,678
  • 5
  • 79
  • 77
  • Thanks for reply. I don't see how does this take care of non-submitting postbacks either, i.e. once I change something I will not be able to do anything that causes postback without a warning. – Victor Feb 08 '10 at 13:57
  • Yes, always a single form, it will be running on a master page. But I don't think can use this method as it is. After I click "Save" submit button following making some changes, I should be able to close a page without a warning, since I just saved my changes. My code above above takes care of that scenario. – Victor Feb 08 '10 at 14:28
  • @Victor I simplified my script a little – Lachlan Roche Feb 08 '10 at 14:30
  • @Lachlan. Yes, see my comment above – Victor Feb 08 '10 at 14:31
  • @Victor You are doing an ajax save? – Lachlan Roche Feb 08 '10 at 14:34
  • @Lachlan. Just a regular save. – Victor Feb 08 '10 at 14:46
  • @Thanks for the update. I know it's hard to take care of all scenarios, but looks like it will reset a dirty state after a postback, caused by any control, other then save button? Besides save button, I have many types of controls on a page, that cause a postback, hence my original post. – Victor Feb 08 '10 at 15:05
  • @Lachlan Please, see my previous comment – Victor Feb 08 '10 at 15:44
  • @Victor postbacks route via form.onsubmit, which will call jquery submit handler. – Lachlan Roche Feb 08 '10 at 15:51
  • @Lachlan Right, so this method will "clean" dirty state on every postback? – Victor Feb 08 '10 at 15:54
  • @Victor if we render a new page, the state is reset. if we performed an AJAX save we would need to reset var serialized – Lachlan Roche Feb 08 '10 at 16:02
  • @Lachlan Thanks for reply. Yes, I am doing a regular save, this is vanilla ASP.NET project. Looks like that state will be reset on every postback which I can't have, i.e. it should reset only when I click Save, not any other control on a page, that causes a postback. – Victor Feb 08 '10 at 16:09
  • Even though this is not exactly what I was asking for, I really appreciate the effort, so I will accept. – Victor Feb 08 '10 at 21:51
1

Have you tried catching the submit event of the form ? (not the click of the submit button, but the actual submit)

maybe this would solve it ..

$('form').submit(function(){isDirty = false;});

unless the normal links also submit the form ...

Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317
0

How about something like this?

$(window).unload(function(event)
{
  if (event.target.nodeName != "SELECT" && event.target.nodeName != "INPUT" ) {
    $('#dirtyFlag').val(previouslyDirty ? '1' : '0');
  }
});
​

If this does not work, can you tell me what's the event.target.nodeName called under various circumstances?

Adhip Gupta
  • 7,063
  • 7
  • 34
  • 46
  • Thanks for reply. Value of event.target.nodeName is always '#document' since I have it on a master page – Victor Feb 05 '10 at 15:43
  • That's surprising. It's been a long time that I have worked with ASP.NET but I thought that the end result for the MasterPage was also HTML. Thus, if there is an event on SELECT (AutoPostback) the browser will always know the correct source of the event. The next thing I can suggest is that all postbacks are fired via a function called `__doPostBack`. You can maybe do something with that. – Adhip Gupta Feb 06 '10 at 11:16