Warn before navigating away using jQuery

I have to relearn this every time I want to do it, so I record it here for my benefit.  You can stop reading now (unless you’re trying to do this yourself).

You’d think jQuery would have a nice little function/event you could hook into to handle this situation.  Unfortunately, as far as I can see (and with 1.2.6), jQuery doesn’t provide an obvious way to do this.  So if you’re here wondering how to do this using jQuery itself, you can stop reading now.

Now that we’ve gotten rid of the people who don’t care, lets get this done.

The Code

With the following html page snippet:

<span class="kwrd">&lt;</span><span class="html">div</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;</span><span class="html">textarea</span> <span class="attr">cols</span><span class="kwrd">="120"</span> <span class="attr">id</span><span class="kwrd">="editor"</span> <span class="attr">name</span><span class="kwrd">="editor"</span> <span class="attr">rows</span><span class="kwrd">="10"</span><span class="kwrd">&gt;&lt;/</span><span class="html">textarea</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;</span><span class="html">button</span> <span class="attr">id</span><span class="kwrd">="subby"</span> <span class="attr">type</span><span class="kwrd">="submit"</span> <span class="attr">value</span><span class="kwrd">="Save"</span><span class="kwrd">&gt;</span>Save<span class="kwrd">&lt;/</span><span class="html">button</span><span class="kwrd">&gt;</span> 

The following script will warn users before browsing away:

&lt;script type=<span class="str">"text/javascript"</span>&gt;
    <span class="rem">// After our HTML has loaded...</span>
    $(document).ready(function() {
        <span class="rem">// disable the submit button until we have something to submit</span>
        $(<span class="str">"#subby"</span>).attr(<span class="str">"disabled"</span>, <span class="str">"disabled"</span>);
        <span class="rem">// when the user types in the editor...</span>
        $(<span class="str">"#editor"</span>).keydown(function() {
            <span class="rem">// enable the submit button</span>
            $(<span class="str">"#subby"</span>).attr(<span class="str">"disabled"</span>, <span class="str">""</span>);
            <span class="rem">// tell the browser to warn before navigating away</span>
            window.onbeforeunload = function() { <span class="kwrd">return</span> <span class="str">"Don't do it."</span>; };});
        <span class="rem">// when the submit button is clicked, disable the warning</span>
        $(<span class="str">"#subby"</span>).click(function() { window.onbeforeunload = <span class="kwrd">null</span>; });
        });
    });
&lt;/script&gt;

What’s going on here?

When the edit page loads, we don’t want the user to submit the exact same thing back to the server, so we disable the submit button.  Also, if nothing’s happened, we don’t want to bug the user about navigating away, so we don’t immediately set that warning.

If the user types in the textarea, we use this indication as a cheap and quick way to indicate that Changes Have Been Made.  Of course, they might be useless changes depending on the context; if you want to do some additional work to determine if a “real” change has been made, go for it.  Also note, this happens every time a keydown event fires in the textarea.  I’m not claiming its good javascript, I just claim it warns the user before losing changes.

So, when the textarea has changes, I enable the submit button (by removing its disabled attribute value), and set the window.onbeforeunload callback function.

Note, you can’t access this function via $(“window”), you have to access it directly.  I can’t tell you what that says about browser support; I can tell you that it works in gte IE7 and Chrome.  And that’s not bad.

This callback function must return a string.  This string is displayed in a warning dialog shown to the user prior to the browser leaving this particular page.

Lastly, when the submit button is clicked, we want to disable this warning lest the user get bugged before we post back to the server.  You can do this by setting the window.onbeforeunload callback function to null.

Caveats

Again, the keydown function I add to the textarea fires every time a key is pressed when the textarea has focus.  I’d fix that, but I’m struggling with posting this from my laptop.  I trust you’ll fix this issue.  Also, since you’re touching the window in javascript directly and not through the soothing jQuery API, you might have issues in some browsers.  I can confirm, agian, that it works fine in IE7 and Chrome.