Search code examples
javascriptjquerydatatableshtml5-history

Enabling History API with datatables


I have a dataTable object on a page representing a list of releases I need to keep track of with the url /releases I want to add the following functionality

  1. if /releases?query=<query>, the dataTable will initialized with the provided query
  2. The query parameter is updated if the user changes the search term
  3. The back and forward buttons in the browser go the appropriate query

So far I am able to do the first 2, but when I listen for the popstate event, redrawing the table triggers a pushState which I can't figure out how to prevent. Here's my code so far:

$(document).ready(function(){
  var prevSearch;
  var table = $('#releases').dataTable({
    "bJQueryUI" : true,
    "sPaginationType" : "full_numbers",
    "iDisplayLength" : 50,
    "oSearch": {"sSearch": '#{params[:query]}'},
    "fnDrawCallback": function(oSettings) {
        var curSearch = oSettings.oPreviousSearch.sSearch;
        if (!prevSearch) {
          prevSearch = curSearch;
        } else if (curSearch != prevSearch) {
          console.log("changed to: " + curSearch);
          history.pushState({query: curSearch}, "title", "releases?query=" + curSearch);
          prevSearch = curSearch;
        }
     }
  });
  window.addEventListener("popstate", function(e) {
    if (e.state) {
      table.fnFilter(e.state.query);          
    }
  });
});

Note, I am using a rails backend and this is inlined javascript being served in the page.


Solution

  • you have only 2 options here:

    • move pushState code out of drawCallback. There must be some other code that causes the datatables to draw when user enters something. put your pushState code there. This is the ideal solution
    • add a hack like this

      $(document).ready(function () {
          var prevSearch;
          var saveState = true;
          var table = $('#releases').dataTable({
              "bJQueryUI":true,
              "sPaginationType":"full_numbers",
              "iDisplayLength":50,
              "oSearch":{"sSearch":'#{params[:query]}'},
              "fnDrawCallback":function (oSettings) {
                  var curSearch = oSettings.oPreviousSearch.sSearch;
                  if (!prevSearch) {
                      prevSearch = curSearch;
                  } else if (curSearch != prevSearch) {
                      console.log("changed to: " + curSearch);
                      if (saveState) {
                          history.pushState({query:curSearch}, "title", "releases?query=" + curSearch);
                      }
                      prevSearch = curSearch;
                  }
              }
          });
          window.addEventListener("popstate", function (e) {
              if (e.state) {
                  saveState = false;
                  table.fnFilter(e.state.query);
                  saveState = true;
              }
          });
      });