How to Make JQuery UI Tabs Linkable and Bookmarkable
With JQuery UI Tabs v.3 there isn’t an option to make the tabs bookmarkable. In other words when you click on the tabs the URL does not change therefore you can’t link or bookmark anything other than the default tab.
Here is how I solved the problem… [UPDATED!]
The old way that I solved this follows but it is such crap I should just delete it. However, I think I will keep it just to show the workings of the iterative development process - if at first you don’t succeed elegantly, try, try again!
The new way I solved this is entirely without any framework intervention - purely in javascript. And it fits the HTML paradigm better as it uses anchors (#) in the URL to reference the tabs!
Here is my entire new initTabs method (see well below for the old method where I show the HTML code snippet that goes along with this code):
function initTabs(){
var tabIndex = {'info':0,'reviews':1,'ratings':2}
var re = /#w+$/; // This will match the anchor tag in the URL i.e. http://here.com/page#anchor
var match = re.exec(document.location.toString());
if (match != null) var anchor = match[0].substr(1);
for (key in tabIndex) {
if (anchor == key) {
selectedTab = tabIndex[key];
break;
}
else selectedTab = 0;
}
tabs = $("#tabs").tabs({selected:selectedTab}); // render the tabs
tabs.bind('tabsshow', function(event, ui) { // when tab is shown update the URL
var re = /#w+$/;
var url = document.location.toString();
// to make bookmarkable
document.location = url.replace(re, "#"+ui.panel.id);
});
}
The following is the old way …
First off, you can’t be doing this in static HTML. You have to be working with a framework that gives you some control over what URL runs which code. I am using my own framework, pyroxide, which allows me to map URLs to controllers in python. Therefore, when I call http://somedomain.com/someplace/tab2 I map someplace to a controller and then pass in tab2 as a parameter. Now that that is done I can conditionally create HTML based on the parameter to mimic an actual unique URL for a tab on the page.
Let’s say we have the following for our tabs:
....
<script type="text/javascript">
$(function() {
$("#tabs").tabs();
});
</script>
<script type="text/javascript" tal:content="selectTab"></script>
<div id="tabs">
<ul>
<li><a href="#info">info</a></li>
<li><a href="#reviews">reviews</a></li>
<li><a href="#ratings">ratings</a></li>
</ul>
</div>
....If you notice the second javascript block, that is where my conditional code is going to be placed. In my case I am using simpleTAL templating so the
tal:content= piece will pass in something from my code. It is just a matter of setting what I want to pass in within the context of the template.
Therefore, if I receive reviews as the parameter for the controller, meaning that the URL was http://mydomain.com/whatevercontroller/reviews I set what I want to pass in to the template as the following:
$(function(){$("#tabs").tabs("select","#reviews");});That way, when the page is loaded JQuery UI will render the tabs and then when the second block of javascript is read it will select the “reviews” tab.
Hi! Could you please elaborate on how to include your newest method in an actual html file? Because im kinda new at this, but I need it desperately.
jQuery can make this even more concise (in 4 lines here for readability)
var anchor = $(document).attr(’location’).hash; // the anchor in the URL
var index = $(’#tabs div.ui-tabs-panel’).index($(anchor)); // in tab index of the anchor in the URL
$(’#tabs’).tabs(’select’, index); // select the tab
$(’#tabs’).bind(’tabsshow’, function(event, ui){document.location = $(document).attr(’location’).pathname + “#” + ui.panel.id;}); // change the url anchor when we click on a tab
thanks man.
your welcome!
thanks for pointing me to the right direction. here’s my 2 cents to the matter.
short n sweet
$(’#my_selector’).tabs({
’select’: function(){$(this).index($(document.location.hash));},
‘load’: function(event, ui){document.location.hash = ui.panel.id;}
});
i used load instead of show, since show had a strange anchoring feature, that i couldn’t override.
Thanks. This article is a great help! I ended up using Sami’s suggested code. Mark Yoon’s suggestion worked, but I ran into the same weird anchor problem that Sami did (page would scroll).
I take my previous comment back. Sami’s suggestion doesn’t seem to work — nothing is passed to the url when I click different tabs. Mark Yoon’s suggested solution works, but it is annoying because the tab menu links behave like anchors in that the page scrolls to the top of the ui-tabs-panel div (hides the top of my page).
Here is a solution I came up with, based on solutions posted above, and using the ‘address’ jQuery plugin: http://www.asual.com/blog/jquery/2009/04/28/introducing-jquery-address.html
Using tabsselect on the bind removes the scrolling issue. Bookmarking, url hash replacement, and autoload from an inline anchor are supported…
var tabs;
tabs = $(’#tabs’);
tabs.tabs(); // initialize tabs
tabs.bind(’tabsselect’, function(event, ui){document.location = $(document).attr(’location’).pathname + “#” + ui.panel.id;});
// change the url anchor when we click on a tab
//add anchor and bookmark support to the ui tabs
$.address.externalChange(function(event) {
// back/forward button handler
var i = $.address.value();
if(i!=”/”){
tabs.tabs(’select’, i);
} else {
tabs.tabs(’select’, 0);
}
});
I’ve used Sami’s solution but only one anchor is working. But others aren’t. I’ll try the last one.