Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome onpopstate / pushState bug?

First of all I'm not entirely sure what I'm doing or expecting is right. There doesn't seem to be much documentation about this, but what I've read suggests that this should work.

I encountered some problems while trying to use history.pushState so I ended up making a demo page to see what was going wrong.

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js" ></script>
<script>

window.onpopstate = function()
{
    var d = new Date;
    console.log(d.toString());
    console.log(document.location.href);
};

$(document).ready(function()
{

    $('#push').click(function()
    {
        var rand = Math.random();
        history.pushState( {'number':rand} , 'Test '+rand , '/test/'+rand );
        return false;
    });

});

</script>

</head>

<body>

<a href="#" id="push">New state</a>

</body>
</html>

When I click the 'new state' link, I'm expecting to see in the console that the onpopstate function has been fired and I'll see a new url (something like test/[number]).

The location in the address bar in chrome does update, but the onpopstate event never fires. Then when I click the back button in the browser, it looks like multiple popstate events are firing. It appears that ever time I use the browser navigation buttons, every popstate event that should have fired is happening all at once.

This is kind of hard to explain. Here's what I expect to see in the console.

Load the page. Chrome fires the initial popstate event on page load

popstate.html:13Sat Nov 19 2011 16:23:48 GMT+0000 (GMT Standard Time)

popstate.html:14http://example.com/popstate.html

Click the 'new state' link. The location in the address bar updates to http://example.com/test/0.06458491436205804.

Sat Nov 19 2011 16:23:53 GMT+0000 (GMT Standard Time)

popstate.html:14http://example.com/test/0.06458491436205804

Click the back button in the browser. The url in the address bar returns to /popstate.html

popstate.html:13Sat Nov 19 2011 16:26:27 GMT+0000 (GMT Standard Time)

popstate.html:14http://example.com/popstate.html

That's what I'm expecting. Here's what I'm ACTUALLY seeing...

Load the page

popstate.html:13Sat Nov 19 2011 16:27:42 GMT+0000 (GMT Standard Time)

popstate.html:14http://example.com/popstate.html

Click the new state link. Nothing appears in console. Address bar changes to /test/0.5458911096211523

Click back button in browser. Address changes back to /popstate.html

popstate.html:13Sat Nov 19 2011 16:27:42 GMT+0000 (GMT Standard Time)

popstate.html:14http://example.com/popstate.html

popstate.html:13Sat Nov 19 2011 16:28:57 GMT+0000 (GMT Standard Time)

popstate.html:14http://example.com/popstate.html

As you can see, it repeats the initial popstate and shows the return to /popstate.html, but it never fires for the pushed sate. If I now press forward in the browser, I get:

popstate.html:13Sat Nov 19 2011 16:27:42 GMT+0000 (GMT Standard Time)

popstate.html:14http://example.com/popstate.html

popstate.html:13Sat Nov 19 2011 16:28:57 GMT+0000 (GMT Standard Time)

popstate.html:14http://example.com/popstate.html

popstate.html:13Sat Nov 19 2011 16:29:58 GMT+0000 (GMT Standard Time)

popstate.html:14http://example.com/test/0.5458911096211523

(They all appear again, here's a screenshot: http://img.ctrlv.in/4ec7da04e20d3.jpg)

I don't know if I'm doing it wrong, my expectations are wrong, or this is actually a bug?

Thanks in advance to anyone who read all of this and can shed some light on it for me.

like image 875
antriver Avatar asked Nov 19 '11 16:11

antriver


2 Answers

Chrome's console.log cannot handle things nicely when you're going to other pages. You can confirm this because it logs several things at once with other timestamps (which cannot be possible). You'd better use $("body").append to log here (or appending to some other element).

Secondly, when you push a state, then obviously it is not popped, so the popstate event is not triggered. If you want to trigger the onpopstate handler when you're pushing a state as well, you can create a simple wrapper like this: http://jsfiddle.net/vsb23/2/.

function load(url, state) { // logging function; normally load AJAX stuff here
    $("pre").append(new Date
                    + "\n" + url
                    + "\n" + JSON.stringify(state) // to log object as string
                    + "\n\n");
}

function pushState(data, title, url) {
    history.pushState(data, title, url);
    load(location.href, data); // call load function when pushing as well
}

window.onpopstate = function(e) {
    load(location.href, e.state);
};

$("button").click(function() {
    pushState({foo: "bar"}, "test", "/test?a=b"); // sample push
});

Edit: This is already a bug on the Chromium bug tracker.

like image 157
pimvdb Avatar answered Oct 10 '22 21:10

pimvdb


if(navigator.userAgent.toLowerCase().indexOf('chrome') > -1 !== true) {
    runpopState();
}

function runpopState() {
    alert("POP STATE");
}

window.onpopstate = function () {
    runpopState();
};

Until they fix the bug, a solution like this will suffice.

like image 43
TaylorMac Avatar answered Oct 10 '22 22:10

TaylorMac