HTML 5 History API with PopState and AJAX keeps re

2019-07-18 09:36发布

问题:

I'm currently loading data onto the page via Ajax updating the url via pushState, no errors. And popstate returns the full object into the console — for viewing purposes.

I'm at the point where the forward and back buttons work partially, meaning, sometimes it will reshow the content when the url changes, but most of the time it simple reloads the page which is stopping the smooth flow of the application.

Been working endless trying to get things to work, without success :(

I just can't figure out why the page keeps reloading and reverting back to the first instance.

I think it might have something to do with the state being or not being set on first viewing of the page.

My code below, which fires an Ajax request on loading then updates the pages content when the dropdown is changed by the user.

$(function() {
"use strict";
var $results  = $('#results');

    // First dataset when page loads
    (function(){
      var x = 'https://swapi.co/api/people/';
      var swFirstCall = $.ajax({
        dataType: 'json',
        url: x,
        async: false
      });
      swFirstCall.done(function(data) {
        var template = $('#results_tpl').html();
        var html = Mustache.render(template, data);
        $results.html(html);
      });
    })();

    // New dataset based on selected category
    $(document).on('change', '#categories', function(e){
      e.preventDefault();
      var category = this.value; // get selected value
      var x = 'https://swapi.co/api/' + category + '/';
      var swChangeCall = $.ajax({
        dataType: 'json',
        url: x,
        async: false
      });
      swChangeCall.done(function(data) {
        var template = $('#results_tpl').html();
        var html = Mustache.render(template, data);
        $('#results').html(html);
        console.log("Category: " + category);

        window.history.pushState(
            // data
            // title
            // url
            category,
            category,
            window.location.pathname + '?page=' + category
            );
      });
    });
    window.addEventListener('popstate', function(event) {
          window.location.href = window.location.href;
          console.log(event);
          return(event);
    });
});

Any help much appreciated. I've searched Stackoverflow, and many other resources though can't understand.

Codepen if it helps viewing code.

Thanks, Barry

回答1:

What you want to do is store the data and category variables in your history state object when you pushState. Later, you will then pull that state out when you trigger a popstate event (user goes back and forward). With the values you get out of the popstate event, you will then need to rerender the page. I made changes to your pushState function and your popstate handler to show how this can be done. Finally, you will want to follow the advice in one of the comments about removing the async: false option in your ajax call - there's no reason you need to hold up the rest of your script execution like this.

EDIT: Forgot to mention that you'll want to initialize your state object on first page load. Use the replaceState method to do this as you don't want to create another history entry. Rather, you want to modify the current history entry to include the category and data you would want to return to when the user goes back to the initial page. See below for your swFirstCall.done method with the replaceState call included.

// ...

swFirstCall.done(function(data) {
  var template = $('#results_tpl').html();
  var html = Mustache.render(template, data);
  $results.html(html);
// initialize history state object
  window.history.replaceState(
    { category: 'Select Category', data  },
    null,
    '',
  );

// ...

window.history.pushState(
  // data
  // title
  // url
  { category, data },
  category,
  window.location.pathname + '?page=' + category
);

// ...

window.addEventListener('popstate', function(event) {
  window.location.pathname + '?page=' + event.state.category;
  var template = $('#results_tpl').html();
  var html = Mustache.render(template, event.state.data);
  $('#results').html(html);
  $('#categories').val(event.state.category);
});

// ..