Search code examples
javascriptajaxbrowser-history

AJAX navigation + window.history.pushState: "back" browser button doesn't work


I have created a litte Javascript tool to support partial loading of contents in a Plone site via AJAX (global AjaxNav object containing all functionality). Of course I'd like the browser history (back and forward buttons) to work, so I have the following little function:

   var set_base_url = function (url) {  // important for local links (hash only)
        var head=null,
            base=$('html base').first();
        if (base) {
            base.attr('href', url);
            log('set base[href] to '+url);
        } else {
            $(document).add('<base>').attr('href', url);
            log('created <base> and set href to '+url);
        }

   var history_and_title = function (url, title, data) {
        var stateObj = {  // can be anything which is serializable, right?
            cnt: increased_state_counter()
            };
        if (typeof data.uid !== 'undefined') {
            stateObj['uid'] = data.uid;
        }
        if (title) {
            if (AjaxNav.options.development_mode) {
                title = '(AJAX) ' + title;
            }
            document.title = title;
        }
        if (url) {
            set_base_url(url);
            window.history.pushState(stateObj, '', url);
        } else {
            window.history.pushState(stateObj, '');
        }
    };
    AjaxNav.history_and_title = history_and_title;

This function is called and doesn't yield any errors (none I could spot, at least); but when I try to go back by clicking the "back" browser button or hitting the backspace key, only the visible url changes, but no content is reloaded. I'd accept full-page reloads for now, but of course reloading pages from the history via AJAX would be even better.

Is there any obvious error?

The whole thing is a little bit lengthy (~ 850 lines, currently) because there often is no way to know whether the target URL specifies an object or it's view method; thus I try up to two URs per hyperlink, and then do the processing (replacing contents, setting the title, event.preventDefault() and the like), or simply return true to load the page as a whole.


Solution

  • Your missing the popstate event listener. While pushState pushes a new history entry to the collection, clicking the back button will pop a state from the history collection. Just like with an array. The popstate event is set to the window object and has access to the state object that you set in the pushState function.

    It is useful to give the state object information on what it should do on the current page. For example, what data you have to fetch to load the current page.

    Try the snippet below in your code and see what it outputs.

    window.addEventListener('popstate', event => {
       const { state } = event;
       console.log(state);
    });