Version 2.0 – HTML5 History

by Matthew, on 9 December 2016

We’ve mentioned before that FixMyStreet is built on a progressively-enhanced base, a concept explained neatly in a nice blog post from the UK government.

This means that e.g. the slippy map is, underneath it all, an old-style server-side image map that works out where you click; URLs are all shareable and pages are functional even if JavaScript is not available; the front page loads quickly and doesn’t need to preload an entire application.

None of this means that we don’t use or like JavaScript, however. This post is about adding JavaScript to FixMyStreet to provide a quicker experience to users looking at reports on our map.

When viewing a list of reports on FixMyStreet, you might want to look at a few reports one after the other, much as you can on a Google Maps or OpenStreetMap results screen.

So now, when you click a report in the list or a pin on the map, the report page is pulled in via JavaScript. This updates the page, pin and URL in situ, rather than loading a new page. Other pins remain visible, plus the page feels (and probably is) a bit quicker as the page header doesn’t reload, and it is easy to switch back to the list view.

This feature uses HTML5’s History API, ie. pushState and popState, to update the URL as the page changes. That means that when you share it, the page that loads will always be the one that the user intended it to be.

This improvement did not come without problems, however. Overriding the browser’s own behaviour when it comes to history and navigation means you have to think carefully, and I’m sure we’ll need to make further refinements to ensure that everything works as the user would expect.

There were small issues: for example, pushState stores the document title at the point when it’s called, for the ‘Back’ button list, meaning we had to make sure any title change happened after that. Some browsers have a popstate on page load, which can cause an issue if you assume it’s only fired due to history events.

There was the complication of needing to tell the difference between someone clicking back to the ‘initial state’ of the page, and an internal hashchange or other less crucial event – as well as using a replaceState on page load, we store the original URL and title for use in such a situation.

Then we forgot that the code would be running on /reports lists as well as /around which led to some confusion until we realised what was happening! And of course, you have to make sure everything JavaScript-wise is set up appropriately for content brought in via JavaScript.

We also used pushState in the new report process, to update the URL as you select the report’s location, and on list pages when you select one of the filters or sort. This has worked well, and is certainly much more preferable to the ‘hash-bang’ technique used by some sites in previous years (and still now), which is reliant on JavaScript functioning.

If you have any questions, or problems installing the code, please do get in touch, or post on our mailing list.