12

I have been trying to get the forward an back browser buttons to work on a small site using pjax and have come up with the following code to handle class changes and fading in and out the various overlays.

However I have found that Chrome and Safari treats the initial page load as a popstate and so it is causing me grief. Is there anyway to stop this?

$(window).on("popstate", function() {
  if ($('body').hasClass('info')) {
    $('body').removeClass("info").addClass("work");
    $('.info_overlay').fadeOut(duration);
    alert('popstate');

  } else if ($('body').hasClass('work')) {
    $('body').removeClass("work").addClass("info");
    $('.info_overlay').fadeIn(duration);    

  } else {
    $('body').removeClass("project").addClass("work");
    $('.project_overlay').fadeOut(duration);
  }
});
John
  • 1
  • 13
  • 98
  • 177
Sam Quayle
  • 537
  • 5
  • 16

5 Answers5

29

Tag the state when you call pushState(), then ignore all popstate events that don't have your tag. e.g.

history.pushState({ myTag: true }, ...)

$(window).on("popstate", function(e) {
  if (!e.originalEvent.state.myTag) return; // not my problem
  // rest of your popstate handler goes here
}

Don't forget to call replaceState at page load so that you can handle the popstate when you get back to the initial page load.

$(function() { history.replaceState({ myTag: true }); });
Sean Hogan
  • 2,902
  • 24
  • 22
  • I actually found that the solution is within pjax. So instead of doing – Sam Quayle May 26 '12 at 20:23
  • That's the only solution i found that works after the first call of a page, after a reload and in gecko/webkit/trident. Plus without changing the behavior browsers calling popstate! Great solution. Thanks! – griffla May 16 '13 at 18:31
  • In my tests today, `event.originalEvent` doesn't exist in any current browsers. While a variation of this (using `event.state`) does seem to work in current versions of Chrome and Firefox, Safari (8.0.6) gets `null` back for `event.state` and I can't find _any_ of the data pushed with `pushState` for later reference. Safari is the new IE6. – Adam Tuttle Jul 01 '15 at 18:25
  • @AdamTuttle `.originalEvent` is a field in jQuery's event object that references the *original* DOM event. See http://api.jquery.com/on/ – Sean Hogan Jul 02 '15 at 03:22
  • Ah, fair enough, thanks! I was working in vanilla JS so didn't have that available. – Adam Tuttle Jul 02 '15 at 12:14
  • Wouldn't the call to `replaceState` ensure that `myTag` is `true` on every page? When would it evaluate to false? – Shreyas Nov 20 '15 at 11:15
  • @Shreyas When a different script calls `pushState` without `myTag`. – Sean Hogan Nov 20 '15 at 21:34
3

I actually found the solution within pjax itself.

Instead of doing:

$(window).on('popstate', function() { ... 

which fired the popstate on the initial page load I did:

$(window).on('pjax:popstate', function() {...  
Artur Filipiak
  • 9,027
  • 4
  • 30
  • 56
Sam Quayle
  • 537
  • 5
  • 16
2

The best long term fix is to up-vote https://code.google.com/p/chromium/issues/detail?id=63040 to get Google to fix this. They've known they're out of compliance with the HTML5 spec for about two years now.

Dave
  • 1,212
  • 12
  • 8
  • 1
    It says `Status: Fixed` and a comment there: "Still not landed on Chrome 32 stable, fixed on Chrome Canary 34." - Feb 10, 2014. – MMachinegun Apr 28 '14 at 11:57
1

In order to solve the initial page load as a popstate in safari and chrome browsers, we can use SetTimeOut function.

This simply works !!

  setTimeout( function() {
      window.addEventListener( 'popstate', myFunction, false );
    }, 500 );
Thiru
  • 37
  • 5
0
var StateHelper = {

    pushState: function(url) {
        if(window.history.pushState) {
            window.history.pushState({"popstate": true}, '', url);
        }
    },

    updateStateData: function(stateData) {
        if(window.history.replaceState) {
            window.history.replaceState(stateData, '', window.location.href);
        }
    }
};

/**
 * NOTE: Webkit fires popstate event initial. So we modify the current state, but in the
 * event we still get null. So we can differentiate.
 */
StateHelper.updateStateData({"popstate": true});
window.addEvent('popstate', function(e) {
    if(e.event.state && e.event.state.popstate) {
        window.fireEvent('pophistory', e);
    }
});

(A mootools solution)

guest
  • 1
  • 2
    Welcome to Stack Overflow! Please explain what your code does and why it will solve the problem. An answer that just contains code (even if it's working) usually wont help the OP to understand their problem. – SuperBiasedMan Jul 15 '15 at 10:26