Demistifying HTML5 history api (hash push)
May 20, 2013 Leave a comment
There are a lot sites about html5 history api, but most of those sites dont even have a fully working example of how about this api works on the fly, many assumptions are being made on this very topic, but just a few examples worth spending time.
This is the main reason I will try to explain how the history api works:
First of all (and as far as I know) there are two main ways to push a state into the history:
1) by calling window.history.pushState(data, url, title).
2) by setting the window.location.hash property usually this approach is used in single page applications.
In this particular post I’m gonna cover the second option.
Let’s get started:
First things first, binding the popstate:
window.onpopstate = function(event) {
loadContent(window.location.hash, true);
};
/*
What?
=====
This basically wires up the built-in onpopstate event with this anonymous function
which calls our 'loadContent' function with the specified hash (remember the hash
is already on the url, because the back/forward button already placed it there,
and the second parameter is what I call 'isPoppingState' in this case (we're on
the onpopstate event) therefore we're indeed popping the state.
*/
You should place the code above inside the document ready.
Let’s address the missing loadContent function:
function loadContent(hash, isPoppingState) {
if(!isPoppingState) {
window.location.hash = hash;
}
showLoader(function() {
processHash(hash, function() {
showPage();
});
});
}
/*
What?
=====
This will set the hash if we're not popping the state (remember setting the hash
is another way to PUSH a state, so if you're setting the hash don't call
`history.pushState`). Then it will call `showLoader` and wait for it's callback,
then it will process the hash and call `showPage` after the `processHash`
callback.
*/
Yes, now you have more missing functions, let’s code them:
function showLoader(done) {
$('head title').html('Loading...');
$('div#page').fadeOut(500, function() {
if(done && typeof(done) === 'function') {
done();
}
});
}
/*
What?
=====
Nevermind.
*/
function processHash(hash, done) {
var title;
var content;
switch(hash) {
case '':
case '#index':
title = Services.IndexService.GetData().Title;
content = Services.IndexService.GetData().Content;
break;
case '#contact':
title = Services.ContactService.GetData().Title;
content = Services.ContactService.GetData().Content;
break;
default:
title = 'Page not found!';
break;
}
if(hash === '') {
hash = '#index';
}
$('section:not(' + hash + ')').hide();
$('section' + hash).show();
$('head title').html(title);
$('header h1').html(title);
$('section' + hash + ' div.content').html(content);
if(done && typeof(done) === 'function') {
done();
}
}
/*
What?
=====
This function will call the corresponding service and fetch the data, after that
it will display, update, hide elements accordingly, at the end it will invoke
its callback if applies.
Did you note the `hash === ''` part, this is just for handling the view since I
need to assume that an empty hash is the index part.
*/
function showPage() {
$('div#loader').fadeOut(500, function() {
$('div#page').fadeIn(500);
});
}
/*
What?
=====
Nevermind.
*/
Okay, now it’s time to mock our services:
Add this to the top of your javascript.
var Services;
And this before any attempt to get data:
Services = new FakeServices();
Yes, you need the FakeServices object, don’t worry, here it is:
var FakeServices = function() {
var indexService = function() {
var getData = function() {
return {
Title: 'Index',
Content: 'Welcome to my HTML5 Single Page Application
with History API via hashtag!'
};
};
return {
GetData: getData
};
};
var contactService = function() {
var getData = function() {
return {
Title: 'Contact',
Content: 'You can contact me at
esteban[dot]murchio[at]gmail[dot]com.'
};
};
return {
GetData: getData
};
};
return {
IndexService: new indexService(),
ContactService: new contactService()
};
};
/*
What?
=====
Javascript objects ftw!
*/
If you would like to bind more ways to go back and forth in your history you could to this:
$('button.back').on('click', function() {
history.back();
});
You might also want to use a global ajax error handler, this could be done like:
$(document).ajaxError(function(event, xhr) {
console.log(xhr.status + ': ' + xhr.statusText);
});
Here is the full example:
http [colon] [slash] [slash] jsbin [dot] com [slash] akizej [slash] 7
The Official Microsoft ASP.NET Site
Recent Comments