Thursday, June 2, 2011

All Your Links Are Belong To Me

I know this is ridiculously simple, but sometimes it's the simple things that just put a smile on a developer's face.

For years clients have had the same requirement for their web applications: "If a user makes changes on a page and navigates away, it should prompt them to save their changes." And for years there have been a number of different responses to this requirement. I've seen everything from "can't be done, the web doesn't work that way" to "we'll just set every control to AutoPostBack=true and store it in Session State" and everything in between. (That second example hurts just thinking about it.)

Being faced with that requirement yet again, a very simple approach just dawned on me. I'm sure I'm not the first person to do it this way, and I'm equally sure that there are better approaches. But this just feels cool...

// Track if the page has unsaved changes.
var unsavedChanges = false;

$(document).ready(function() {
  // Hijack all anchor tags and move their links to a custom attribute.
  $('a').each(function() {
    // Because i is one more than h, of course
    $(this).attr('iref', $(this).attr('href'));
    $(this).attr('href', '#');
    $(this).click(function() {
      if (unsavedChanges) {
        var conf = confirm('You have unsaved changes. Are you sure?');
        if (conf) {
          window.location.href = $(this).attr('iref');
        }
      } else {
        window.location.href = $(this).attr('iref');
      }
    });
  });

  // If anything changes, mark it as an unsaved change.
  $('input, textarea').change(function() {
    unsavedChanges = true;
  });

  // If the user saves a change, they no longer have unsaved changes.
  // (This isn't really necessary here because the save buttons on
  //  this page trigger post-backs, so the value will be reset anyway.
  //  But keep this here in case it's needed on other implementations.)
  $('input[id*=btnSave]').click(function() {
    unsavedChanges = false;
  });
});

(I guess it doesn't handle the back button, but then what does?)