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.
[...] found a solution on Rootsmith Inc’s blog. Especially sami‘s comment helped me: 1 2 3 4 $(’#my_selector’).tabs({ [...]
Non scrolling solution with adding hashes to url: (trick is in prefixing tabs)
var selectedTab = 0; $('#tabs li a').each(function(index) { if ($(this).attr('href').replace("#", "#tab-") == document.location.hash) { selectedTab = index; } }); $('#tabs').tabs({ 'select': function(event, ui){ document.location.hash = "tab-" + ui.panel.id; }, 'selected' : selectedTab });Hey all,
I came up with this simple hack to stop the annoying scrolling prob… Basically, trick the links into displaying your “pretty” name (ex: #mytab) , while the functionality relies on your “ugly” name (ex: #mytab_x)
Javascript
———————
$(document).ready(function() {
// initialize tabs
var $tabs = $(“#tabs”).tabs();
$tabs.tabs(‘select’, document.location.hash+”_x”);
$(“#tabs”).bind(‘tabsshow’, function(event, ui){
document.location.hash = ui.panel.id.replace(“_x”,”");
});
});
HTML
—————-
Tab 1
Tab 2
Tab 3
[content 1 ]
[content 2 ]
[content 3 ]
Hey all,
I came up with this simple hack to stop the annoying scrolling prob… Basically, trick the links into displaying your “pretty” name (ex: #mytab) , while the functionality relies on your “ugly” name (ex: #mytab_x)
is there any chance to change the location in the adress bar? If someone clicks on the tab with #foo I want to have URL change to example.htm#foo
thanks
This works:
// initialize the tabbed interface with a default method set to update
// the url when tabs are clicked (this makes bookmarking possible)
tabs = $(“#tabs”).tabs({
‘select’: function(event, ui){document.location.hash = ui.panel.id;}
});
// now start by selecting the tab that corresponds to the url hash
// if the hash does not match a tab the first tab will be selected by default
tabs.tabs(‘select’,document.location.hash);
I think there is typo on the line:
var re = /#w+$/;
Should be:
var re = /#\w+$/;
Thanks!
I found a great page on how to change the list item image using jQuery. It is super simple and more browser compliant than css.
http://www.ajaxera.com/jquery-change-li-hover/
Mikkel’s solution worked for me. Thanks.
[...] Anyway, no matter if the content should be shown in one page, in tabs or in any other way we had to be able to link to the different subitems directly. As I prefer standard HTML using anchors seemed the way to go, anchors works fine in a plain scrollable page but it could also be used in JQuery tabs. [...]
Its worked.
Thanks,
I’m new to javascript and had a heck of a time getting this to work. I finally figured it out but I had to make a few changes:
function initTabs() {
var tabIndex = {‘scripting’:0,’scripting-history’:1,’equipment’:2,’syslogs’:3,’misc’:4}
// This will match the anchor tag in the URL i.e. http://here.com/page#anchor
// Use .+? instead of \w so you can match on anchors that contain – or _
var re = /#.+?$/;
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;
}
}
// render the tabs
tabs = $(“#tabs”).tabs({selected: selectedTab});
// when tab is shown update the URL
tabs.bind(‘tabsshow’, function(event, ui) {
// to make bookmarkable
var re = /#tabs-/;
window.location.hash = ui.tab.hash.replace(re, “#”);
});
}
Scripting
Scripting History
Equipment List
Syslogs
Misc
tab content here
etc, etc for the other tabs
initTabs();
So when I click on my “Scripting History” tab the url is changed to index.php#scripting-history which I can bookmark. When I load the bookmark initTabs will load my tabs-scripting-history tab.
One thing I found was a bit of jquery code that will change the url for you too. This feels much faster than doing it in initTabs. To use this remove the following lines from initTabs:
// when tab is shown update the URL
tabs.bind(‘tabsshow’, function(event, ui) {
// to make bookmarkable
var re = /#tabs-/;
window.location.hash = ui.tab.hash.replace(re, “#”);
});
And add this to .ready(function()
$(document).ready(function() {
// This converts “#tabs-foo” to “#foo” so that initTabs() can
// then find #foo and select the appropriate tab
$(‘#tabs’).tabs({
select: function(event, ui) {
var re = /#tabs-/;
window.location.hash = ui.tab.hash.replace(re, “#”);
}
});
});
I’m new to javascript and had a heck of a time getting this to work. I finally figured it out but I had to make a few changes:
function initTabs() { var tabIndex = {'scripting':0,'scripting-history':1,'equipment':2,'syslogs':3,'misc':4} // This will match the anchor tag in the URL i.e. http://here.com/page#anchor // Use .+? instead of \w so you can match on anchors that contain - or _ var re = /#.+?$/; 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; } } // render the tabs tabs = $("#tabs").tabs({selected: selectedTab}); // when tab is shown update the URL tabs.bind('tabsshow', function(event, ui) { // to make bookmarkable var re = /#tabs-/; window.location.hash = ui.tab.hash.replace(re, "#"); }); } Scripting Scripting History Equipment List Syslogs Misc tab content here etc, etc for the other tabs initTabs(); So when I click on my "Scripting History" tab the url is changed to index.php#scripting-history which I can bookmark. When I load the bookmark initTabs will load my tabs-scripting-history tab. One thing I found was a bit of jquery code that will change the url for you too. This feels much faster than doing it in initTabs. To use this remove the following lines from initTabs: // when tab is shown update the URL tabs.bind('tabsshow', function(event, ui) { // to make bookmarkable var re = /#tabs-/; window.location.hash = ui.tab.hash.replace(re, "#"); }); And add this to .ready(function() $(document).ready(function() { // This converts "#tabs-foo" to "#foo" so that initTabs() can // then find #foo and select the appropriate tab $('#tabs').tabs({ select: function(event, ui) { var re = /#tabs-/; window.location.hash = ui.tab.hash.replace(re, "#"); } }); });I’m new to javascript and had a heck of a time getting this to work. I finally figured it out but I had to make a few changes:
function initTabs() { var tabIndex = {'scripting':0,'scripting-history':1,'equipment':2,'syslogs':3,'misc':4} // This will match the anchor tag in the URL i.e. http://here.com/page#anchor // Use .+? instead of \w so you can match on anchors that contain - or _ var re = /#.+?$/; 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; } } // render the tabs tabs = $("#tabs").tabs({selected: selectedTab}); // when tab is shown update the URL tabs.bind('tabsshow', function(event, ui) { // to make bookmarkable var re = /#tabs-/; window.location.hash = ui.tab.hash.replace(re, "#"); }); } Scripting Scripting History Equipment List Syslogs Misc tab content here etc, etc for the other tabs initTabs();So when I click on my “Scripting History” tab the url is changed to index.php#scripting-history which I can bookmark. When I load the bookmark initTabs will load my tabs-scripting-history tab.
One thing I found was a bit of jquery code that will change the url for you too. This feels much faster than doing it in initTabs. To use this remove the following lines from initTabs:
// when tab is shown update the URL tabs.bind('tabsshow', function(event, ui) { // to make bookmarkable var re = /#tabs-/; window.location.hash = ui.tab.hash.replace(re, "#"); }); And add this to .ready(function() $(document).ready(function() { // This converts "#tabs-foo" to "#foo" so that initTabs() can // then find #foo and select the appropriate tab $('#tabs').tabs({ select: function(event, ui) { var re = /#tabs-/; window.location.hash = ui.tab.hash.replace(re, "#"); } }); });Sorry for triple posting…I was trying to get the div and ul html code to display
just use this code within
$(‘#tabs’).tabs();
$(‘#tabs ul li a’).click(function () {location.hash = $(this).attr(‘href’);});
});
and you are done.