Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to catch a state change event ONCE with history.js?

I have an example code below where if you click the links, then use back and forward, each state change will cause more and more hits on the statechange event. Instead of the one that I expect.

Links:

  • https://github.com/browserstate/history.js
  • http://docs.jquery.com/Downloading_jQuery

Code:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>History start</title>
</head>
<body>
    <h1>Headline</h1>
    <hr>
    <div id="menu">
        <ul>
            <li>
                <a href="page-1">Page 1</a>
                <div style="display:none;">
                    <h2>Page 1</h2>
                    <p>Content 1</p>
                </div>
            </li>
            <li>
                <a href="page-2">Page 2</a>
                <div style="display:none;">
                    <h2>Page 2</h2>
                    <p>Content 2</p>
                </div>
            </li>
        </ul>
    </div>
    <hr>
    <div id="content">
        <h2>Start page</h2>
        <p>Paragraf</p>
    </div>
    <script src="external/jquery-1.6.2.min.js"></script>
    <script>if ( typeof window.JSON === 'undefined' ) { console.log("Loaded json2"); document.write('<script src="external/json2.js"><\/script>'); }</script>
    <script src="external/history.adapter.jquery.js"></script>
    <script src="external/history.js"></script>
    <script>
    $(document).ready(function() {
        History.enabled = true;

        $('a').each(function() {
            $(this).click(function(e) {
                e.preventDefault();
                var $link = $(e.target),
                    state = {'href': $link.attr('href'), 'title': $link.html()},
                    $div = $link.siblings('div'),
                    content = $div.html();

                $('#content').html(content);

                History.pushState(state, state.title, state.href);
                
                return false;
            });
        });
        
        History.Adapter.bind(window, 'statechange', function() {
            var State = History.getState();
            // remove double hit on event
            console.log(State);

        });

    });
    </script>
</body>
</html>
like image 679
Alexander Morland Avatar asked Oct 13 '11 08:10

Alexander Morland


2 Answers

It's because you're calling the pushState function when you load the page, which also causes a statechange. I was in a similar situation and used a but a boolean before my pushStates so I knew I was doing a pushState. It looks like this...

historyBool = true;
History.Adapter.bind(window,'statechange',function(){ // Note: We are using statechange instead of popstate

var State = History.getState(); // Note: We are using History.getState() instead of event.state

    //don't run our function when we do a pushState
    if(historyBool){
        historyBool = false;
        tempFunction = new Function(State.data.ajaxRunFunction);
        tempFunction();
    }
    historyBool = true;
});

historyBool = false;
historySet = {ajaxRunFunction: "upc('" + pageID + "','')"};
History.pushState(historySet,"","");
like image 177
Jared Avatar answered Oct 02 '22 15:10

Jared


While not relevant to your specific problem, I had a scenario where I needed to unbind the event handler from the History Adapter. To do so you can unbind the "statechange" event from window, which is what History.Adapter binds to when you call History.Adapter.bind() :

$(window).unbind('statechange.namespace');

You can added a namespace to the event to avoid unbinding other unrelated event handlers as above, or use a named function to unbind that function specifically. To use the above namespace, you would need to bind the handler using the same namespace, ie

History.Adapter.bind(window,'statechange.namespace',function(){...}
like image 32
lvanzyl Avatar answered Oct 02 '22 15:10

lvanzyl