Hi Folks! Recently, I was working on a web application and I was thinking of making extensive use of AJAX so that the whole page would not have to be loaded again and again. These days single page web applications(SPA) are becoming quite popular. We load a main page in the browser and all the subsequent request are made using an AJAX by leveraging XMLHttpRequest object. In this way, only a portion of a page is updated and it is quite faster and also enhances User Experience(UX).

Everything sounds good. Right ? But there is a catch!!

The main drawback is the use of the back and refresh button. Suppose you click a link, a HTTPRequest is fired, whole page is loaded and the URL is changed.Let’s call this “State 1”. When you click on another link that triggers a XMLHTTPREQUEST (AJAX), it fetches the content from the server and updates a portion of a page(A div). Let’s call it “State 2”. You click on some other link and it again fetches some other content and updates the same div. Let’s call it “State 3”.

Now when you click browser’s refresh button, the “State 1” is loaded and the changes rendered by the State 2 and State 3 are lost. Why ?? This happens because the content is loaded via Ajax and the DOM state is changed without the URL that points to the page that has changed after ajax request. Suppose after “State 1” our browser pointed to URL jellyfish.com/controllerA/actionA . When we made 2 Ajax request our URL is still same. So, when I press refresh a request will be fired at the same URL and the initial page would be rendered again.

So what should be done ? URL should be changed after AJAX request. Right ? But how ?

We need to find a way to change the URL when we make an AJAX request. The change in the URL must not trigger a page reload. Also, the change in the URL must be detected by javascript code and it must trigger an AJAX request so that the dynamic changes are loaded again when page is refreshed or back button is hit.

We will use a concept known as hash fragment.

hash fragment

 

We can append the hash this way:


window.location.hash = '#hash-url-content';

We will append the hash fragment on each link that triggers an AJAX request and on the hash change event the javascript code will parse the hash fragment and make an ajax call to update the state of the page.  The hash fragment should contain the necessary information required to trigger an AJAX call.

 

urlChange

 

URL hash 1

Let us look at the figure above to understand how it would be done.When we make a normal request, we get a response and the main page gets loaded, then JavaScript on the page would read and parse the hash fragment and trigger,load the ajax content. The hash fragment is not sent to the server. It is only known to the browser. Only the main part of the URL is sent to the server. For example: If the URL is grails.com/gorm/#part-1/hql then only “grails.com/gorm/” will be sent to the server and the hash part “#part-1/hql” will be interpreted by the client-side code to determine the ajax call in case a page is refreshed.

 

back-button hash

When the user clicks back button, hashChange event should be triggered and code must be invoked which should read the hash and make an AJAX request.

 

We use the onHashChange event to trigger the ajax call. We can catch the event like this:

window.onhashchange = function () { ...  }

 

Older browsers does not have support to handle onHashChange event. In order to make it backward-compatible we can use setInterval method to continuously check for a changed hash.

 

Alternate Solution

Instead of manually handling the ajax request, we can simply use HTML5 History API. History API provides us with a method for handling this. If we want to change the URL we can call this method and everything will be taken care of.

 


history.pushState(url, title, data)

 

The History API also provides a callback called onpopstate. You can write a javascript function and assign it to window.onpopstate, which is responsible for reconstructing the original page.

 

html5 api

 

I have pushed the code on github. Here is the link.

I hope you find this blog post useful 🙂