75

I have to detect if a user has clicked back button or not. For this I am using

window.onbeforeunload = function (e) {
}

It works if a user clicks the back button. But this event is also fired if a user clicks F5 or the reload button of the browser. How do I fix this?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
facebook
  • 1,894
  • 3
  • 21
  • 28

6 Answers6

67

So as far as AJAX is concerned...

Pressing back while using most web applications that use AJAX to navigate specific parts of a page is a huge issue. I don't accept that 'having to disable the button means you're doing something wrong' and in fact developers in different facets have long run into this problem. Here's my solution:

window.onload = function () {
    if (typeof history.pushState === "function") {
        history.pushState("jibberish", null, null);
        window.onpopstate = function () {
            history.pushState('newjibberish', null, null);
            // Handle the back (or forward) buttons here
            // Will NOT handle refresh, use onbeforeunload for this.
        };
    }
    else {
        var ignoreHashChange = true;
        window.onhashchange = function () {
            if (!ignoreHashChange) {
                ignoreHashChange = true;
                window.location.hash = Math.random();
                // Detect and redirect change here
                // Works in older Firefox and Internet Explorer 9
                // * it does mess with your hash symbol (anchor?) pound sign
                // delimiter on the end of the URL
            }
            else {
                ignoreHashChange = false;
            }
        };
    }
}

As far as I’ve been able to tell, this works across Chrome and Firefox.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Gus Crawford
  • 1,017
  • 8
  • 18
  • This uses the [History API](https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history) not [supported everywhere](http://caniuse.com/#search=history). You can add a [shim](https://github.com/balupton/history.js) though, but you'd have to change a little bit your code. – Florian Margaine Apr 07 '12 at 01:13
  • 1
    You're totally right. I looked it up and I can get older FF and IE working with this model.. (edited above) Look at this guy's post: http://www.adequatelygood.com/2010/7/Saner-HTML5-History-Management – Gus Crawford Apr 07 '12 at 03:39
  • My solution is a bit too simple your link references a great cross-platform solution *i beleive* based on the same hashchange event. – Gus Crawford Apr 07 '12 at 03:52
  • The solution makes you use the `onstatechange` custom event, which corresponds to the `onpopstate` when supported, and fallbacks to the `onhashchange`. – Florian Margaine Apr 07 '12 at 09:13
  • Very cool dude thx for ur insight! – Gus Crawford Apr 07 '12 at 14:44
  • Nice solution, this worked great aside an ajax app I'm currently developing. Thanks. – Jim22150 Feb 05 '13 at 08:36
  • So how do you redirect now if you confirm that you want to browse back – AAlferez Feb 25 '14 at 18:06
  • This code snippet works great – Adam Strudwick May 09 '14 at 19:35
  • @AnnArbor87 I remember wanting to tackle this... I actually got programming web-apps again I'm going to revisit this and figure that out... – Gus Crawford Jul 31 '14 at 19:25
  • @Adam Strudwick: Haven't revisited this answer for a while, I'm happy to see it helped! – Gus Crawford Jul 31 '14 at 19:25
  • 1
    1. You should add `history.go(-2);` inside the window.onpopstate event if you wish to only catch the event but keep the original back button behavior. 2. I think window.onhashchange would work only if URL contains "#" anchor – BornToCode Mar 08 '15 at 12:46
  • 1
    This would not be worked in IE9 if there is no hash in the address (onhashchange event never fire). Dont forget to add a default hash before register the event. – Wittaya Apr 24 '15 at 08:17
61

Please try this (if the browser does not support "onbeforeunload"):

jQuery(document).ready(function($) {

  if (window.history && window.history.pushState) {

    $(window).on('popstate', function() {
      var hashLocation = location.hash;
      var hashSplit = hashLocation.split("#!/");
      var hashName = hashSplit[1];

      if (hashName !== '') {
        var hash = window.location.hash;
        if (hash === '') {
          alert('Back button was pressed.');
        }
      }
    });

    window.history.pushState('forward', null, './#forward');
  }

});
Benny Code
  • 51,456
  • 28
  • 233
  • 198
  • The function `window.history.pushState` is a child / a method of the object `window.history`. Would it not suffice to test for the function only? – Oliver Schafeld Apr 11 '16 at 12:45
  • 1
    @OliverSchafeld testing `window.history.pushState` only (or first) could throw `Cannot read property 'pushState' of undefined` if the browser doesn't implement the history API. So the two tests are needed, in this particular order. – Nico Prat Apr 28 '16 at 14:21
  • @Nico Prat : Ah, of course, thanks. Testing for a nonexistent property like this `!!window.history.madeupproperty` results `false`. So I was guessing`if(!!window.history.pushState)` might do. Couldn't get my hands on an IE9 (http://caniuse.com/#feat=history) for proper testing. But simply checking `!!window.notexistent.madeup` throws 'Cannot read property...' error. So `if (window.history && window.history.pushState)` is truly required and in that order as well. – Oliver Schafeld May 07 '16 at 09:34
  • Works for me in Chrome, FF & IE11 – Greg Trevellick Jul 05 '17 at 14:10
  • 2
    Very usefull code, but, as @Portekoi pointed out, not block twice the back button. To achieve the full blocking feature, I added the last line `window.history.pushState('forward', null, './#forward')` after `alert('...')` row. This did the trick... no refresh or any noticiable effect on backbutton click. – Nowdeen Jul 10 '17 at 19:54
9

The best way I know:

window.onbeforeunload = function (e) {
    var e = e || window.event;
    var msg = "Do you really want to leave this page?"

    // For Internet Explorer and Firefox
    if (e) {
        e.returnValue = msg;
    }

    // For Safari / Chrome
    return msg;
};
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Marco Allori
  • 3,198
  • 33
  • 25
  • 2
    This is not working in chrome. – Riz Dec 03 '16 at 12:38
  • 2
    This will not *disable* the back button as much as it blocks any browsing (back, forward, refreshing) and allows the user to stop it with a prompt that is out of your control. – Gus Crawford Mar 30 '17 at 16:56
  • 1
    This disables navigating away from the page - including closing the page, back, and forward and does not answer the question. – Danger Jun 12 '18 at 16:07
7

I'm detecting the back button this way:

window.onload = function () {
if (typeof history.pushState === "function") 
{
    history.pushState("jibberish", null, null);
    window.onpopstate = function () 
    {
        history.pushState('newjibberish', null, null);
        // Handle the back (or forward) buttons here
        // Will NOT handle refresh, use onbeforeunload for this.
    };
}

It works, but I have to create a cookie in Chrome to detect that I'm on the page the first time, because when I enter the page without control by a cookie, the browser does the back action without clicking on any back button.

if (typeof history.pushState === "function") 
{
    history.pushState("jibberish", null, null); 
    window.onpopstate = function () {
        if (((x = usera.indexOf("Chrome")) != -1) && 
              readCookie('cookieChrome') == null) 
        {
            addCookie('cookieChrome', 1, 1440);      
        } 
        else 
        {
            history.pushState('newjibberish', null, null);  
        }
    };
}

And very important, history.pushState("jibberish", null, null); duplicates the browser history.

How can I fix it?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alexandra
  • 155
  • 2
  • 4
  • 15
4

Since the back button is a function of the browser, it can be difficult to change the default functionality. There are some workarounds though. Take a look at this article:

Q311 How do I disable the "Back" button of a browser?

Typically, the need to disable the back button is a good indicator of a programming issue/flaw. I would look for an alternative method like setting a session variable or a cookie that stores whether the form has already been submitted.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
James Hill
  • 60,353
  • 20
  • 145
  • 161
  • 15
    If you do anything remotely modern, the back button's default action is not appropriate. This is because the back button is a workaround for the impracticality of the web before ajax. – Morg. Oct 22 '13 at 11:59
3

I'm assuming that you're trying to deal with Ajax navigation and not trying to prevent your users from using the back button, which violates just about every tenet of UI development ever.

Here's some possible solutions:

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
bpeterson76
  • 12,918
  • 5
  • 49
  • 82
  • No, actually i have a form and after submitting the form i am redirecting user to another page.SO , here i do not want to user to click back button and go to form page. – facebook Jun 15 '11 at 14:35
  • 3
    @ibh: Perhaps the [Post/Redirect/Get (PRG) pattern](http://en.wikipedia.org/wiki/Post/Redirect/Get) suits your needs. – Marcel Korpel Jun 15 '11 at 14:44
  • 3
    Wouldn't it be easier if you just let them go to the page but upon clicking the button you set a variable (or a session, or cookie) that tells the app not to present the form any more? You could simply hide the form and offer another "thanks for already filling out the form page" Or, redirect automatically if that variable has been set. It would prevent them from navigating in the way that they originally came as well. – bpeterson76 Jun 15 '11 at 14:44
  • @ibh: Or send the form using Ajax (with a normal, non-JavaScript fallback), so you can let the form disappear after success, without adding a new page to the browser history. – Marcel Korpel Jun 15 '11 at 14:55