Prevent a Webpage from Navigating Away Using JavaScript

Prevent a webpage from navigating away using JavaScript

Using onunload allows you to display messages, but will not interrupt the navigation (because it is too late). However, using onbeforeunload will interrupt navigation:

window.onbeforeunload = function() {
return "";
}

Note: An empty string is returned because newer browsers provide a message such as "Any unsaved changes will be lost" that cannot be overridden.

In older browsers you could specify the message to display in the prompt:

window.onbeforeunload = function() {
return "Are you sure you want to navigate away?";
}

Prevent user from accidentally navigating away

Sorry there's no technical solution to your "problem."

It's not an accident when a user decides to leave your site, i.e. by typing a new URL, so stopping them to say "Hey, you haven't checked out yet" is kind of pointless.

Is there a way to prevent leaving a webpage with the browser back button?

As far as I know, short of using fake url's as @keith suggested, there isn't much you can do to control them. The navigation buttons exist outside the realm of our total control seeing as they are a part of the browser itself and not the webpage, therefore they can't be explicitly halted on our request. These are things built into the browser that really should not be messed with as you don't want to cause unpredictable behavior. It is smarter to develop your application around this fact rather than try and combat it.

In addition, to all that, you do not want to be intrusive on the browser. As soon as you start dealing with things you didn't explicitly create or were given access to, you're crossing a line into the land of assumption and that is a very dangerous place as I've come to learn.

If you are trying to keep a stateful system then that can be managed on the back end on a user to user basis that is not intrusive at all and makes for a pleasant user experience that doesn't impede normal browser operation,

Prevent user to navigate away with unsaved changes

I've managed to find a solution to this, although some more work is required. For this solution, I am assuming that you keep track when a view is dirty.

There are 4 main ways of moving out of a view;

  1. Click on a link on the view
  2. Click on link outside the view
  3. Click on refresh or external link
  4. Click on back/forward on the browser

1. Application link

This is the easiest case. When you click on your own link, you have to check if your view is dirty. For example, I have an in-app back button that is handled by a historyBack function. On the view:

historyBack: function() {
if (this.isDirty) {
answer = confirm("There are unsaved changes.\n\nDo you wish to continue?")

if (answer) {
this.isDirty = false
window.history.back()
}
}

else {
window.history.back()
}
}

2. Links outside your view

This type of interaction can be handled by extending the Router prototype's execute method, not the navigate method as proposed in other places.

There should be a variable somewhere accessible by the Router that stores the state of the view. In my case, I'm using the Router itself and I update this variable every time I change the dirty flag on the view.

The code should look something like this:

_.extend(Backbone.Router.prototype, {

execute: function (callback, args, name) {
if (Backbone.Router.isDirty) {
answer = confirm "There are unsaved changes.\n\nDo you wish to continue?";

if (!answer) {
return false;
}
}

Backbone.Router.isDirty = false
if (callback) callback.apply(this, args)
}
}

3. Refresh or external link

Refresh and external links actually unload your Javascript so here the solutions based on beforeunload (see question) actually work. Wherever you manage your view, I use a controller but let's assume it's on the same view, you add a listener on show and remove it on destroy:

onShow: function() {
$(window).bind("beforeunload", function (e) {
if (this.isDirty) {
return "There are unsaved changes.";
}
}
}

onDestroy: function() {
$(window).unbind("beforeunload");
}

4. Back/Forward on the browser

This is the trickiest case and the one I haven't figured out completely yet. When hitting back/forward, the user can navigate out of the app or within the app, both cases are covered by the code on 1 and 3, but there is an issue I can't figure out and I will create another question for it.

When hitting back/forward, the browser changes the address bar before calling the router so you end up with an inconsistent state: The address bar shows a different route to the application state. This is a big issue, if the user clicks again on the back button, after saving or discarding the changes, she will be taken to another route, not the previous one.

Everything else works fine, it shows a pop up asking the user if she wants to leave or continue and doesn't reload the view if the user chooses to stay.



Related Topics



Leave a reply



Submit