Bookmarkable Ajax-Driven Pages

Kate Greenaway illustrations as bookmarks via Emmie_Norfolk on Pixabay

If someone might reasonably expect to bookmark or link others to content, I like that to be possible. With ajax-updated pages it doesn’t come for free, though. The newest addition to the Utilities repository is a little bit of get/set code for query strings to support bookmarkability.

The code consists of two functions, parseQuery and updateQuery. They should live inside a scope (perhaps a self-executing anonymous function) with variables holding the default and current values of the parameters that determine the content of the page.

var default1 = "default1";
var param1;

Parsing queries is straightforward and can be done in multiple ways. This version uses a regular expression to grab everything between the parameter name with equals sign, and the next ampersand if any, provided that’s at least one character long.

function parseQuery() {
  var queryString = window.location.search.substr(1);
  // set all parameters to their default values
  param1 = default1;
  if (queryString.length > 0) {
    // if there's a query string, check for each param within it
    var val1 = queryString.match(/.*param1=([^&]+).*/i);
    if (val1) {
        param1 = val1[1];
    }
  }
}

To handle multiple parameters you’d repeat the blocks right after the comments: set all variables to the default, and then do a match and a length check for each of them within the single “if there’s a query string” check.

You can also split the query string into an array, but it’s a little more difficult to deal with exceptional cases like parameter names that lack values.

Updating the query is more complicated. I wanted my query string to consist of parameters with non-default values only, plus any parameters that don’t belong to this code. My original version simply rewrote the whole query string to consist exactly of all the parameters – default or not – and would not permit other parameters to persist, such as those that you might use to track (or deactivate) A/B tests. The reason to keep default parameters out of the query string was that one of those had a default value dependent on the date; if you bookmarked the “now” version of the page I wanted it to still be “now” when you came back a month later.

The answer was once again regular expressions (when is it not?).

function updateQuery() {
  var newUrl = window.location.href;
  // clean out valueless parameters to simplify ensuing matching
  newUrl = newUrl.replace(/(.*[?&])param1(&(.*))?$/, "$1$3");
  if (param1 !== default1) {
    if (newUrl.match(/[?&]param1=/)) {
      newUrl = newUrl.replace(/(.*[?&]param1=)[^&]*(.*)/, 
      '$1' + param1 + '$2');
    } else if (newUrl.indexOf('?') > 0) {
      newUrl = newUrl + '&param1=' + param1;
    } else {
      newUrl = newUrl + '?param1=' + param1;
    }
  } else {
    newUrl = newUrl.replace(/(.*[?&])param1=[^&]*&?(.*)/, '$1$2');
  }

  // tidy up
  if (newUrl.match(/[?&]$/)) {
    newUrl = newUrl.slice(0, -1);
  }    
  window.history.pushState('', '', newUrl);
}

For each parameter in turn, clean out any valueless instance of it (meaning “without an equals sign”, really; if the browser allows valueless with an equals sign is will be handled in the if statements). Then, if the parameter has a non-default value, replace its value or add it as a new parameter to the string. If it is the default, remove it from the string. That is, the whole section between the two comments would be repeated for each parameter. All of this business might leave a trailing question mark or ampersand, so clean that away if needed and push the new URL into the browser history.

There’s a sample webpage in the repo as well, in which you can try this out, though you’ll need to update the internal links on the page to match its location on your localhost.


Kate Greenaway illustrations as bookmarks via Emmie_Norfolk on Pixabay.

Leave a Reply

Your email address will not be published. Required fields are marked *