Home > Uncategorized > How to make jQuery tabs play nicely with Sammy.js

How to make jQuery tabs play nicely with Sammy.js

jQuery tabs are very easy to use. In the HTML you do something like:

<div id="someTabs"> 

    <ul> 
        <li><a href="#firstTab">First Tab</a></li> 
        <li><a href="#secondTab">Second Tab</a></li> 
    </ul> 

    <div id="firstTab">
        Content for first tab...
    </div> 

    <div id="secondTab">
        Content for second tab...
    </div>

</div>

You can then use a bit of script to get tabs:

mainTabs = $('#someTabs').tabs();

One nice thing about this is that “intra-document” links of the form #abc will cause the browser to scroll to show the element with the ID abc so it still does something almost useful for users who have JavaScript switched off (although personally I’m not a convinced hard-liner on that issue – I believe its long overdue for JavaScript to be used to develop fully-fledged rich client applications, not just optionally-enhanced web pages.)

Meanwhile, Sammy is a wonderful library for managing your use of intra-document links. You register handler functions like this:

this.get('#management/user/:userName', function(ctx) {

    var userName = ctx.params.userName;

    // update the state of the document, e.g. display
    // management info related to userName
});

The string passed to get is a URI pattern, so this handler will run whenever the user navigates to an in-document link conforming to that pattern. Those in-document link identifiers are thus reinterpreted as true “local URLs”, assumed to be divided up into a slash-delimited path. A colon prefix identifies a variable piece of the path, the value of which can then be obtained from the ctx parameter, as shown above. And you can do whatever you like in your handler to update the actual state of the DOM (or any hidden state stored in JavaScript variables).

What’s the advantage of this? You make the state changes of your UI into navigation – exactly as you would in a traditional pure HTML/HTTP application. Now you have perfect integration with the browser’s history feature, and can structure your application in a way that takes full advantage of AJAX without breaking the usage patterns of the web: back button, deep linking, it all just works.

But what happens if you mix together Sammy and jQuery tabs? It’s quite likely that within one tab there will be several states that the user can navigate through, especially if you use the tabs at the top level as the basis for navigation. This means that you need to record tab switches in the browser history.

However, the jQuery tabs function intercepts the clicks on the tab links, and just changes the visibility of associates div elements. No navigation actually occurs so the browser doesn’t record the state change in its history. So if the user starts on tab 1, makes some navigation changes within it, and then switches to tab 2, they will find that pressing the back button does not take them back to tab 1. Instead it reverses the recorded navigation change inside tab 1 – which the user can’t currently see!

The solution is pretty simple. Firstly, create the tabs like this:

mainTabs = $('#someTabs').tabs({
        select: function(ev, ui) {
            location.href = ui.tab.href;
            return true;
        }
    });

By providing a custom select handler, we can easily ask the browser to record the tab’s link ID string as a navigation. This will also cause the associated Sammy handlers to execute.

Then in the Sammy handler, we need to ensure that the right tab is selected. This means that when the user hits the Back button, the tab will change:

this.get('#management/user/:userName', function(ctx) {

    mainTabs.tabs('select', 0); // select the 'management' tab (index 0)

    var userName = ctx.params.userName;

    // update the state of the document, e.g. display 
    // management info related to userName
});

This change must be repeated in every handler relating to the navigation state beneath a tab: recall that there may be several different handlers for in-document URLs under “management”, and any one of them may be the first to be revealed by pressing the back button.

It’s not very nice to be using positional indexes in this way, especially with the repetition. This problem could be avoided easily by organising the in-document URL paths so that they always begin with the ID of the tab that they are associated with, e.g. both of these would be under the #management tab:

  • #management/globalpermissions
  • #management/user/:userName

This would allow you to write a function that automatically figures out which tab to switch to.

Advertisements
Categories: Uncategorized Tags: , ,
  1. August 18, 2010 at 11:10 am

    I’m trying this, but can’t get Sammy to respond on back/front navigation. Do you have a full version of the example that I can poke at? My code looks like this:

    Agenda
    FAQ

    Agenda goes here

    FAQ in here

    $(function() {
    var mainTabs = $(“#tabs”).tabs({
    select: function(ev, ui) {
    location.href = ui.tab.href;
    return true;
    }
    });
    $.sammy(function() {
    alert(‘Setting up sammy’);
    this.get(‘#agenda’, function(context) {
    // mainTabs.tabs(‘select’, ‘#’ + this.params[‘tab’]);
    alert(‘Tab switch to agenda’);
    mainTabs.tabs(‘select’, 0);
    });
    });
    });

    I’ve tried this.get(‘#:tab’), but that didn’t work, so tried explicitly listening to #agenda, but that doesn’t work wither. Sammy appears to be loading correctly, because there are no console errors.

    I’m using jQuery UI 1.8.4 and Sammy 0.5.4. The tabs work and the URL updates to include #anchors. Loading the page with an anchor opens the correct tab, but navigating back and forth doesn’t switch tabs.

    What gives?

  2. August 18, 2010 at 11:22 am

    How dumb of me. I forgot to get Sammy going with .run();

  3. January 19, 2011 at 4:29 am

    This looks really promising – can’t wait to try it out. Will report back, cheers!

  4. November 27, 2012 at 7:29 pm

    Two years later and this post still helped me out! Thanks. FYI There is a breaking change in new jquery ui 1.9 so same thing would not work. However it still works for 1.8.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: