javascripthtmlhtml5-historypopstate

Why does the popstate event not fire?


I am trying to understand the popstate event in JavaScript and for that I created this simple AJAX-based navigation website.

Here's home.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Home</title>
</head>
<body>
    <header>
        <a href="index.html">Home</a>
        <a href="about.html">About</a>
    </header>

    <div id="main">
        <h1>Home Page</h1>
        <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Repellendus eligendi suscipit aliquid. Mollitia ratione impedit ab, dicta reprehenderit veniam nam facere ipsam vel minus doloribus officia, odit dolorum alias error.</p>
    </div>
    <script src="nav.js"></script>
</body>
</html>

Here's about.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>About Us</title>
</head>
<body>
    <header>
        <a href="index.html">Home</a>
        <a href="about.html">About</a>
    </header>

    <div id="main">
        <h1>About</h1>
        <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Architecto placeat ipsam nam nobis exercitationem voluptatibus, officia impedit. Dolore, esse dignissimos enim porro aspernatur sit aperiam asperiores, maiores, hic velit quod.</p>
    </div>
    <script src="nav.js"></script>
</body>
</html>

And here's the script nav.js:

// implementing ajax-based navigation
var main = document.getElementById('main');

function makeRequest(url, callback) {
    var xhr = new XMLHttpRequest();
    xhr.responseType = 'document';
    xhr.open('GET', url);
    xhr.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            callback(this);
        }
    }
    xhr.send();
}

window.onclick = function(e) {
    if (e.target.href != window.location.href) {
        history.pushState(null, '', e.target.href);
    }

    makeRequest(e.target.href, function(xhr) {
        document.title = xhr.responseXML.title;
        main.innerHTML = xhr.responseXML.getElementById('main').innerHTML;
    });
    e.preventDefault();

    window.onpopstate = function(e) {
        console.log('The popstate event has fired')
        makeRequest(window.location.href, function(xhr) {
            main.innerHTML = xhr.responseXML.getElementById('main').innerHTML;
        });
    }
}

The problem I am facing is detailed as follows:

  1. I go to a new tab and open up the document index.html. This is the first entry in the tab's history.

  2. On this page, I click the link pointing to about.html. As a result, the window.onclick handler gets fired and ultimately, using AJAX, the document about.html gets dynamically displayed. The browser's title also gets changed, as well as the URL (which happens due to history.pushState()).

  3. Now I go back (using the back button of the browser), the URL changes to index.html, and consequently the popstate event fires on window. Here, I reload the contents of index.html into the current document and everything works fine.

  4. I go back, which takes me to the home page of Google Chrome (the start of every new tab).

  5. Now, I go forward. This takes me to the document index.html. What is displayed on the browser are the contents of index.html. So uptil this point, everything is working fine.

  6. I go forward again. The browser's URL changes to about.html and its title as well. However, this time, the popstate event doesn't fire. The URL has changed to a location which was set earlier on using history.pushState() so I expect the popstate event to fire. However, it doesn't.

What is the reason for the popstate event not firing on the last forward step?


Solution

  • Your window.onpopstate = function(e) { block should be outside the window.onclick = function(e) { block.