Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

History.js getState() at pageload

I'm a little confused about how History.js works at page-load. I've done a few experiments but the results seem indeterministic.

My website is a search engine and the query is stored in the URL parameters: ?Query=cats. The site is written purely in javascript. History.js works great when I do a new search, the new query is updated, and the state is pushed.

My problem is how to create an initial state if the user manually enters in a URL including a Query parameter. Every way I try to do this ends up resulting in running the search query twice in some case. The two use-cases that seem to conflict are:

  1. User manually enters URL (mydomain.com?Query=cats) into address bar and hits enter.
  2. User navigates to an external page, and then clicks the back button

In both cases, the javascript loads, and therefore looks to the URL parameters to generate an initial state.

However, in the second case, History.js will trigger the statechange event as well.

Necessary code:

    History.Adapter.bind(window,'statechange',function() { // Note: We are using statechange instead of popstate
        var s = History.getState();
        if(s.data["Query"]){
          executeQuery(s.data);
        }
    });

and in $(document).ready I have

  // Get history from URL
  s = getQueryObjectFromUrl(location.href);
  if(s["Query"]){
      History.pushState(s,'',$.param(s))
  }

Is there a better way to handle creating an initial state from URL parameters?

like image 866
CambridgeMike Avatar asked Nov 03 '22 17:11

CambridgeMike


2 Answers

As I had a similar problem to to yours, what i did was to define the function bound to a statechange as a named function, and then all I had it running when the page load as well.

It worked better than trying to parse the URI or anything else, hope it helps.

like image 98
Fabiano Soriani Avatar answered Nov 08 '22 17:11

Fabiano Soriani


This is the way I chose to do it (based on Fabiano's response) to store the initial state parameters

var renderHistory = function () {
    var State = History.getState(), data = State.data;
    if (data.rendered) {
        //Your render page methods using data.renderData
    } else {
        History.replaceState({ rendered: true, renderData: yourInitData}, "Title You Want", null);
    }
};
History.Adapter.bind(window, 'statechange', renderHistory);
History.Adapter.onDomLoad(renderHistory);

Of course if you are using a different on DOM load like jquery's you can just place renderHistory(); inside of it, but this way doesn't require any additional libraries. It causes a state change only once and it replaces the empty initial state with one containing data. In this way if you use ajax to get the initData inside the else, and it will not need to get it the next time the person returns to the page, and you can always set rendered to false to go back to initial page state / refresh content.

like image 25
vipero07 Avatar answered Nov 08 '22 18:11

vipero07