My talk at the 2nd jQuery Manchester Meetup
This is an overview of the talk I did for the 2nd jQuery Manchester meetup on the 8th March 2011. What I was trying to do was introduce some of the basics to jQuery including its selectors, chaining, animation, events and ajax. It sparked some pretty good discussion following the talk, particularly around the controversial hashbang. Also, you can check out the code at this github repository. Without much further ado, here it is.
The first thing we need to do is add jQuery to our page, we’re going to be using the copy hosted by google api’s
<script src="//ajax.googleapis.com/ajax/libs
/jquery/1.5.1/jquery.js"></script>
Now, we can test to see if this has been loaded by our page. Open up your browser and launch its developer console and type in jQuery.fn.jquery. All being well, we should get back our version number 1.5.1. OK, so the first thing we want to do within our script file is to add the document ready function. This means that we wait until all the elements of the DOM are loaded before we run our jQuery.
$(document).ready( function () { });
Once we’re at this stage, we are going to want to add some functionality to our navigation. What we’re going to do here is set their opacity to 0.5, when the user hovers over the nav item we are going to set the opacity to 1. This will distinguish between a hovered item, and an item that isn’t being hovered on. OK, so we’re going to want to make some selections, as these may be used more than once we are going to cache our selectors in variables. The two we will be making are the navigation li elements, and the navigation a elements.
var $navli = $( ‘#mainNav’ ).find( ‘li’ ) , $nava = $navli.find( ‘a’ ) ;
To turn the opacity of our li elements to 0.5 we’re going to use the .css() method.
$navli.css({ opacity : 0.5 });
Using the .css() method, we can set any number of attributes, we just need to separate our key / value pairs with a comma. In this example though, we only need to set the opacity. The next thing we need to look at is adding behaviour for when our users hover over the li elements. We’re going to chain our method to our .css() method.
$navli.css({ opacity : 0.5 }) .hover( function() { $(this).animate({ opacity : 1 }); }, function() { $(this).animate({ opacity : 0.5 }); });
You can see we are using the .animate() method as opposed to .css() on the elements when hovered. This animates our hover from 0.5 opacity to 1 and then back to 0.5 when not hovering. The next thing we are going to do is define our navigations click events. What we want to happen here is the user clicks the link and we go and get the content from its page to display it in our sites #main container. For this we are going to use ajax. OK, let’s set up the click event.
$nava.click( function ( event ) { event.preventDefault(); loadPage( $( this ).attr( ‘href’ )); });
There are two things happening in this snippet, first we are preventing the default action of the click i.e. stopping it loading the page. Secondly, we are passing the elements href to the function loadPage. We need to define what loadPage does; this is where our ajax comes into play.
var loadPage = function(incurl) { $.ajax({ url : incurl }) .success( function( data ) { alert(‘success’); }) .error( function() { alert( ‘error’ ); }); };
What our ajax function is doing here is attempting to get the data from the incoming url. Using our new ajax methods from jQuery 1.5 we can specify what happens when this is a success or when it is a failure. We can also run code on complete. We don’t want an alert to tell us the page exists, we want to load this info into our page. So we alter the code in the .success() method to this:
$(‘#main’).html(data);
Also, if our specified url returns an error (i.e. 404) then we change our code to this:
$( ‘#main’ ).html( ‘This page does not exist!’ );
We can make this a little bit more exciting by adding some animation. As standard we can use fade or slide animations. For this example we are going to be using the slide animation. So our success code now becomes:
$( ‘#main’ ).slideUp( function() { $( this ).html( data ).slideDown(); });
We can run the same code in our error function. We can see here that the code is pretty much identical in each function. So to keep our code as DRY (Don’t Repeat Yourself) as possible we will create a new changePage function.
var changePage = function( incData ) { $( ‘#main’ ).slideUp( function() { $( this ).html( incData ).slideDown(); }); };
OK, so now we can safely navigate through our site, but we might want to let our user know which page they are currently on. We are going to create another function which sets the current page. What this function is going to do is loop through each of our navigation items, if the url is equal to the clicked href then we add the class active.
var currentPage = function( incurl ) { $nava.each( function() { var $this = $(this); if ( $this.attr(‘href’) === incurl) { $this.parent().addClass( ‘active’ ); } }); };
You may have noticed we added in the .parent() method. Here we are traversing the DOM to find the parent element of the a element we’re currently looking at. If the strings match, we give that li element the class active. You’ll notice when we click the element now, we’re leaving all the previously clicked links with a class of active. We want to stop this, to do that, we add the following to our code:
$this.parent() .addClass( ‘active’ ) .siblings() .removeClass( ‘active’ );
And we add the function into our click handler.
$nava.click( function ( event ) { event.preventDefault(); loadPage( $( this ).attr( ‘href’ ) ); currentPage( $( this ).attr( ‘href’ ) ); });
Ok we’re starting to look good, but there is still one pretty big problem, the user cannot use their back button. We’re going to get a bit of help for this one and use Ben Alman’s hash change plugin. A watered down version of his bbq plugin, but it has all we need for this particular problem. So, let’s listen out for the hash change event.
$(window).bind( ‘hashchange’, function() { var hash = window.location.hash ? 'pages/' + window.location.hash.split( '!' )[1] + '.html' : 'pages/gandalf.html'; });
If the window doesn’t currently hold a hash identifier on its url, then we will use the default pages/gandalf.html. You may notice the .split( ‘!’ )[1] in use on our variable, this is so we strip the ! from our string to be usable within our changePage function. OK, so what we do now is remove the function calls from our click event, and add them into the hashchange event. So we end up with this.
$(window).bind( ‘hashchange’, function() { var hash = window.location.hash ? 'pages/' + window.location.hash.split( '!' )[1] + '.html' : 'pages/gandalf.html'; loadPage(hash); currentPage(hash); });
We need to change the # on our click event, so we put this code in here:
$nava.click( function ( event ) { event.preventDefault(); window.location.hash = ‘!’ + $( this ).data( ‘who’ ); });
Lastly, to get everything up and running, we trigger the first hash change event ourselves. This will run through and go to our default Gandalf page, good times.
$(window).trigger( ‘haschange’ );
And that is pretty much that. We’ve pimped up our navigation to give us a fully functioning ajaxy web site with full back button and bookmarking support. Obviously there are drawbacks, if the user doesn’t have javascript enabled then we’re not going to look so hot, but if we plan for these fallbacks then all is good.