19

I have made a solution for my website which includes using ajax to present the general information on the website. In doing this, I am changing the URL every time a user loads some specific content with the window.history.pushState method. However, when I press backspace or press back, the content of the old url is not loaded (however the URL is loaded).

I have tried several solutions presented on SO without any luck.

Here is an example of one of the ajax functions:

$(document).ready(function(){
$(document).on("click",".priceDeckLink",function(){
    $("#hideGraphStuff").hide();
    $("#giantWrapper").show();
    $("#loadDeck").fadeIn("fast");
    var name = $(this).text();
    $.post("pages/getPriceDeckData.php",{data : name},function(data){
        var $response=$(data);
        var name = $response.filter('#titleDeck').text();
        var data = data.split("%%%%%%%");
        $("#deckInfo").html(data[0]);
        $("#textContainer").html(data[1]);
        $("#realTitleDeck").html(name);
        $("#loadDeck").hide();
        $("#hideGraphStuff").fadeIn("fast");
        loadGraph();
        window.history.pushState("Price Deck", "Price Deck", "?p=priceDeck&dN="+ name);
    });
});

Hope you guys can help :)

Amnestic
  • 650
  • 2
  • 8
  • 23

3 Answers3

31

pushState alone will not make your page function with back/forward. What you'd need to do is listen to onpopstate and load the contents yourself similar to what would happen on click.

var load = function (name, skipPushState) {
  $("#hideGraphStuff").hide();
  // pre-load, etc ...

  $.post("pages/getPriceDeckData.php",{data : name}, function(data){
    // on-load, etc ...

    // we don't want to push the state on popstate (e.g. 'Back'), so `skipPushState`
    // can be passed to prevent it
    if (!skipPushState) {
      // build a state for this name
      var state = {name: name, page: 'Price Deck'};
      window.history.pushState(state, "Price Deck", "?p=priceDeck&dN="+ name);
    }
  });
}

$(document).on("click", ".priceDeckLink", function() {
  var name = $(this).text();
  load(name);
});

$(window).on("popstate", function () {
  // if the state is the page you expect, pull the name and load it.
  if (history.state && "Price Deck" === history.state.page) {
    load(history.state.name, true);
  }
});

Note that history.state is a somewhat less supported part of the history API. If you wanted to support all pushState browsers you'd have to have another way to pull the current state on popstate, probably by parsing the URL.

It would be trivial and probably a good idea here to cache the results of the priceCheck for the name as well and pull them from the cache on back/forward instead of making more php requests.

numbers1311407
  • 33,686
  • 9
  • 90
  • 92
  • Thanks for this answer, it is helpful. You mentioned support issues. What is the current state of this as it stands today? – Brian Peterson Nov 22 '13 at 19:50
  • 2
    I can't speak with authority on this but according to [mozilla's info](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history), window.history made it into chrome v5 but the state property didn't appear til v18. Other modern browsers seem to have supported state from the introduction of history. – numbers1311407 Nov 22 '13 at 19:58
  • 1
    Works only single back, also no forward button. – happy_marmoset Sep 30 '16 at 06:38
  • 1
    Solved: seems need to add check if this is back button call to `load()`, if it is then not to push state. – happy_marmoset Sep 30 '16 at 06:53
  • In my case it wasn't working because i was binding the popstate event to the `document` instead of the `window`... Replacing that made it working... Thanks – LukeSavefrogs Jan 30 '19 at 08:38
  • 1
    Pro tip: in the `popstate` listener function's `if` conditional, you can add `else { window.location.reload(); return; }` so that when you reach your starting page it will reload without any url params. – cfx Apr 05 '19 at 18:15
7

This works for me. Very simple.

 $(window).bind("popstate", function() {
    window.location = location.href
  });
Simon Meyborg
  • 727
  • 1
  • 6
  • 7
  • This still has one of the same problems as the original: works only single back, also no forward button. The OP solved the problem by adding a check to see if this is the back button call to `load()`, but this is a custom check and will change based on how you have your page setup. – JonathanDavidArndt Apr 30 '21 at 17:26
0

Have same issue and the solution not working for neither

const [loadBackBtn, setLoadBackBtn] = useState(false);

useEffect(() => {
    if (loadBackBtn) {
       setLoadBackBtn(false);
       return;
    } else {
   const stateQuery = router.query;
    const { asPath } = router;
    window.history.pushState(stateQuery, "", asPath);
},[router.query?.page]
Mayar Ahmed
  • 35
  • 1
  • 7