Drupal in the trenches: AJAX history makes my brain hurt

Many websites use asynchronous Javascript and XML (AJAX) to provide all sorts of whizbang improvements, such as smooth interaction without page reloads. It took me a week to figure out how to do all the effects specified in our information architecture document: callouts, modal dialogs, in-page calendar navigation, and so on. I was pretty happy with what I did, considering it was my first serious work with JQuery.

Then my project manager said, “If I go to the event details page from the month view and hit back, it takes me to the day view instead.”

I said, “Welcome to the wonderful world of AJAX. This might be tough to fix.”

Making the back button work in AJAX applications requires a lot of effort. It doesn’t look like people have a nice and clean solution for it yet, although there are a number of libraries that try to address the situation.

Following the principle of progressive enhancement, I had built all the plain HTML functionality first, then layered the Javascript on top of it using jQuery callbacks. In addition to ensuring that the site still works even if Javascript is disabled, this approach also helps make sure that I have proper URLs for almost all the webpages involved. (I didn’t bother with explicitly transient pages like the year navigator or the day pop-up.)

I started with this Hijax-based approach, because it had the most documentation. I had problems getting it to behave, though, because my AJAX pages have other AJAX links that fail with the history-remote plugin. The history_remote plugin works by replacing all the links with the current page and a code (#remote-1, for example). When the back button is pressed, the library looks for the appropriate link and triggers the click event. This breaks down when the link isn’t actually on the first page. For example, when a user switches from a week to a month view, then goes to the next month, the plugin can’t find the link to the next month on the week view’s page, which is where the user started.

What I really needed to do is encode more information in the URL. If I encode information in the anchor portion of the URL (#…), I can use that to request the page and put that into the appropriate div. For example, if I pass in #transitions_content?new_path=connect/calendar/2009/05 , I might be able to parse that and put the content of new_path into the transitions_content div.

I started going down that rabbit-hole, and then I got myself thoroughly confused, so I decided that the best way would be to just rip out the major AJAX navigation and go back to the simple stuff (which fortunately still works).

Gah. Brain hurts!

Does anyone have a clean way to do this?

  • Nick Lewis

    You could rig Hijax to remember and replicate a sequence of links. But that would get ugly quickly, particularly when it remembers lots of clicks that aren’t actually necessary in order to get back to where the user wants to be. Although you could just make that a feature.. instant replay!

    The best way to me seems just to do your own parsing of the anchor portion of the URL and figure out how to interpret it. You already have the information available (somewhere you’ve written code to load the data you need to reload). So it’s just a matter of implementing a bit of Javascript to prepare the appropriate data on page load.

    A good way to do this easily would perhaps be to have a well-defined mapping between the names of server-side resources from which you’re loading data and the hashtags you’re saving. So then the process becomes: read hashtag, transform into URL, load data from URL and populate.

    To be fair, I haven’t actually done this before, and I may just be repeating what you said you’ve tried and didn’t work, but it sounds reasonable to me…..

  • I’have same problem on my project made with symfony. I want to do the same uri like facebook or other site made with ajax. Parse uri and load content on my object.
    I’m trying to do this with my hand :)
    PS : sorry for my english

  • Paul

    http://www.seaside.st handles all that, but it lacks Drupal or an equivalent and is smalltalk. But you can AJAX everywhere and the back button keeps up.

  • How’s this different? Well first, we make use of the jQuery.post function rather than using the lower level jQuery.ajax with POST specified as an argument. There is an equally useful jQuery.get option if we wanted to use a GET request instead. Note the form:first selector, obviously that would only grab the data for the first form on the page but since there is only one form in the example HTML we’re ok.

  • Tushar Parekh

    Use AddHistoryPoint() method of ScriptManger by enabling history paramer. And then implement onNavigate event, which will fire on Back Buttons event. And inside OnNavigate event, get state of ur previous Ajaxified page using HistoryEventArgs.

    For details try googling this words and you will find better articles then what I wrote.

  • I realise this was ages ago, but the jQuery history plugin was just what you needed. It handles the browser history using the anchor portion of the URL, and all you have to do is provide a function that takes the anchor portion as an argument and loads the relevant AJAX state (although the documentation is so sparse it took me a long time to figure that out).