Question

I have an ajax based application (ie no page 'reloads` when getting new data).

Initially I wanted to find a way to prevent navigation when unsaved data was present on a form.

I came across window.onbeforeunload.

That didn't work when clicking a links (where content is loaded via ajax and pop/push state changes the url).

I added some handling of the a links but need to use the default window.onbeforeunload to cover the standard means of leaving a page (ie manually entering a new URL or using the back/forwards buttons).

The code below works for:

  • a links
  • page refresh
  • manually entering a new url

But is not triggering window.onbeforeunload when using the back button (in Chrome and Firefox).

Is there something awry with the implementation below or is window.onbeforeunload not meant to be triggered when using the back button?

var save_state = true;

// on entering data into an input field, the save button fades in 
// and the save_state changes
$(document).on('keypress', '.class1 input', function() {
if (save_state) {
$(".save_button").fadeIn();
save_state = false;
};
// bind the click event to 'a' (overiding normal link behaviour)
$( "a" ).bind( "click", function(e) {
if (save_state == false) {
e.preventDefault();
alert("Save before leaving.");
// stop the other 'a' bound handlers from being triggered
e.stopPropagation();
return;
}
});
// also cover standard actions when user tries to leave page
// (back/forward or entering a new url manually etc)
window.onbeforeunload = function() {
return 'Save before leaving.';
};
}); 

// when clicking save, fade out the button and revert the save_state
$(document).on('click', '.save_button button', function(e) {
e.preventDefault();
$(this).parent().fadeOut();
save_state = true;
// 'unbind' onbeforeunload
window.onbeforeunload = null;
});

Edit:

After reading this post, I think it is based on the ajax nature of the app:

As long as you stay within your app, because it's a single-page app, it doesn't by definition unload, so there's no beforeunload event.

So I think I may need to look at other ways to trigger the event on back/forwards buttons.

Was it helpful?

Solution

I looked in to triggering window.unload on popstate but didn't have any luck with that.

I ended up changing the logic so that as soon as changes were made, they were saved in the database.

I was using selectize.js for the form input handling and just added some extra calls to it.

In selectize.js (here):

if ($target.hasClass('create')) {
    self.createItem();
} else {
    value = $target.attr('data-value');

became:

if ($target.hasClass('create')) {
    self.createItem();
    $(".saved_message_div").fadeIn(400).delay(2000).fadeOut(400); // new
    updateDatabaseFunction(); //  new
} else {
    value = $target.attr('data-value');
    $(".saved_message_div").fadeIn(400).delay(2000).fadeOut(400); // new
    updateDatabaseFunction(); // new

AND (here):

while (values.length) {
    self.removeItem(values.pop());
}

self.showInput();

became:

while (values.length) {
    self.removeItem(values.pop());
}

$(".saved_message_div").fadeIn(400).delay(2000).fadeOut(400); // new
updateDatabaseFunction(); // new
self.showInput();

And in my own script, the prompt for deleting selectize.js items stayed the same:

onDelete: function(values) {
confirm(values.length > 1 ? 'Are you sure you want to remove these ' + values.length + ' items?' : 'Are you sure you want to remove "' + values[0] + '"?');
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top