Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

weird issue with pushState/popstate - initial page seems to have been "pushed" twice

I'm having a weird issue with pushState/popstate where it seems my initial page is saved twice.

It's a bit hard to explain without an example.

something like this:

  1. current page is www.bing.com
  2. copy/paste my URL into URL bar and page loads
  3. click on a link on the page (this link fires an AJAX request which then manipulates the DOM to display the data retrieved.)
  4. press back button which brings me to the same page as in step2
  5. press back button again but I'm still on the the same page as step2/4
  6. press back button again and this bring me back to www.bing.com

As you can see, I need to press the back button twice to get me back to www.bing.com when it should have only needed 1.

a short explanation of my page (code is at the bottom of the page):

  1. when the page loads, initial list for the dropdown selection is retrieved via AJAX and populates the select tag.

  2. user has option to click on 3 links which determine the contents of the dropdown selection. Example: If I click on Option B link, this fires the same AJAX from step1 but only retrieves data suitable for Option B.

  3. The user makes a selection from the dropdown and presses search. This triggers another AJAX function which retrieves the relevant data and displays the formatted information inside the mysearchresults div.

  4. I tried playing around with placement (e.g. before or after AJAX call) of pushState and the placement now seems the one that give me the least problem. Although I do encounter the issue I mentioned above.

Here's my code. I had to strip out a lot of code/functions to make it short and readable but please be assured the AJAX calls/data display are working.

<div id="content">
    <p>
        <a class="coursetype" href="#" data-type="B">Option B</a>
        | <a class="coursetype" href="#" data-type="H">Option H</a>
        | <a class="coursetype" href="#" data-type="BG">Option BG</a>
    </p>

    <form id="myform">
        <label class="formlabel" for="course">Select your course</label>
        <br /><select id="course" name="course"></select>
        <button id="searchbutton" type="button">Search Me</button>
    </form>

    <div id="mysearchresults"></div>
</div>

$(document).ready(function() {
    var onClickCourseTypeHandler = function(event) {
        event.preventDefault();

        getCourses({ type:$(event.target).data("type") });

        window.history.pushState({ html:$("#content").html(), coursecode:$("#coursecode").val() }, "", main?type="+pagevars.type);
    }

    var onClicksearchbuttonHandler = function(event) {
        if ($("#coursecode").val().length > 0) {
            searchDB({ course:$("#course").val() });

            window.history.pushState({ html:$("#content").html(), coursecode:$("#coursecode").val() }, "", "/main?&course="+$("#course").val());
        }
    };

    $(document).on("click", ".coursetype", onClickCourseTypeHandler);

    $(document).on("click", "#searchbutton", onClicksearchbuttonHandler);

    try {
        window.addEventListener("popstate", function(event) {
            if (event.state) {
                $("#content").html(event.state.html);

                if (event.state.coursecode.length > 0) {
                    if ($("#course option[value='" + event.state.course + "']").length > 0) {
                        $("#course").val(event.state.course);
                    } else {
                        $("#course option:first-child").attr("selected", "selected");
                    }
                }
            }
        });
    } catch(exception) {
    }

    onLoad();

    function onLoad() {
        getCourses({ type:"" });

        window.history.pushState({ html:$("#content").html(), course:dbvars.course }, "", "/main");
    }

    function searchDB(parameters) {
        $.ajax({
            url: baseurl+"/searchDB"
            , cache: false
            , dataType: "json"
            , data: { format:"json", course:parameters.course }
            , success: function(data, status) {
                parameters.data = data;
                displaySearchResults(parameters);
            }
        });
    }

    function getCourses(parameters) {
        if (typeof(parameters.cacheflag) === "undefined") { parameters.cacheflag = false; };

        $.ajax({
            url: baseurl+"/getCourses"
            , cache: parameters.cacheflag
            , dataType: "json"
            , data: { format:"json", coursetype:parameters.type }
            , success: function(data, status) {
                parameters.data = data;
                populateCourses(parameters);
            }
        });
    }
});
like image 423
mrjayviper Avatar asked Apr 24 '15 14:04

mrjayviper


People also ask

Does history pushState reload page?

But this function is not intended to reload the browser. All the function does, is to add (push) a new "state" onto the browser history, so that in future, the user will be able to return to this state that the web-page is now in.

What triggers Popstate?

The popstate event will be triggered by doing a browser action such as a click on the back or forward button (or calling history. back() or history. forward() in JavaScript). Browsers tend to handle the popstate event differently on page load.

What is the difference between pushState and replaceState?

replaceState() operates exactly like history. pushState() except that replaceState() modifies the current history entry instead of creating a new one. replaceState() is particularly useful when you want to update the state object or URL of the current history entry in response to some user action.

What does Window history pushState do?

The history. pushState() method allows you to add an entry to the web browser's session history stack.


3 Answers

When you load your page, it gets added to the History, so when you do history.pushState it's added a second time. Try replacing history.pushState with history.replaceState in the onload function.

like image 78
mantish Avatar answered Oct 02 '22 17:10

mantish


I noticed your using hashes (#) in your hrefs. Try changing the hashes (#) in your a hrefs to Javascript:void(0).


    Javascript:void(0);

Hashes(#) in href will have an effect your pushState/popState.

like image 23
mbejda Avatar answered Oct 02 '22 17:10

mbejda


Pass an object literal to pushState() on page load. This way you can always go back to your first created pushState.

Add to DOM ready

var obj = { html: '', coursecode: '' };

try {
    window.history.pushState({
        html: $("#content").html(),
        coursecode: $("#coursecode").val()
    }, 'just content or variable', window.location.href);
} catch (e) {
    console.log(e);
}

In your eventhandler to push state:

var onClicksearchbuttonHandler = function(event) {
    if ($("#coursecode").val().length > 0) {
        searchDB({ course:$("#course").val() });

        obj.html = $("#content").html();
        obj.coursecode = $("#coursecode").val();
        window.history.pushState(obj, "", "/main?&course="+$("#course").val());
    }
};

When going back to your original pushstate:

$(window).on('popstate', function (ev) {
    var originalState = ev.originalEvent.state || obj.html;
    if (!originalState) {
        // no history
        // do something
        return;
    } else {
        // do something
    }
});
like image 39
Tim Vermaelen Avatar answered Oct 02 '22 17:10

Tim Vermaelen