Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

activate tab based on url hash #581

Closed
wants to merge 1 commit into from

17 participants

Peter Theill dorgan@donaldorgan.com F A T Danny van Kooten David Larlet Taylor Boyko Matt Gates Dan Sully Chip Hayner alvioshki 令狐葱 Francisco Costa adibreaban Raúl Ferràs mrfosip Giovanni Lovato Chris Rebert
Peter Theill

selects a tab if a hash is available in url and hash matches one of the tab names

dorgan@donaldorgan.com

The only addition other addition that would need to be made is the default action of clicking the link would need to happen so that the changing of a tab adds a hash to the URL

F A T
Admin
fat commented

Don't want to add this - i went down this road once and it's really hard to provide consistent behavior down to ie7. Also, like @dorgan said I think we would need to get it working with urls all together

F A T fat closed this
dorgan@donaldorgan.com

I implemented this with a cookies and the change event. I will post the code later. Then your serverside can determine whether or not to add the active class or not.

Peter Theill

ok. @dorgan I would love to see that code, thanks.

dorgan@donaldorgan.com

#mainnav is the ul element of the tabbar

$('#mainnav').tabs().bind('change', function (e) {
    var parts = decodeURI(e.target).split('#');
    $.cookie('cur_tab',parts['1']);
});

I am using a jquery cookie plugin for this BTW.

Piotr Okoński pokonski referenced this pull request
Closed

Tabs and hashtag #700

Danny van Kooten

Just to be clear, @fat what exactly is the problem regarding inconsistency down to IE7?

I was looking for this behaviour and ended up here. Changed bootstrap-tabs.js a little and things seem to work fine in all browsers listed on Bootstrap's main page. Here is the code I used.

In bootstrap-tabs.js I added a line to add the hash to the URL. The slash is there to prevent jumping to the mentioned element.

if ( /^#\w+/.test(href) ) {
    e.preventDefault()
    window.location.hash = '/' + href.substr(1);
    ...

Then, on pages that implemented tabs all I had to do was check the hash and trigger a click on the link element with the corresponding hash, if it exists..

if (window.location.hash) {
    $(".tabs li a[href='#" + window.location.hash.substr(2) + "']").click()
 }

I'm probably overlooking something and as I'm pretty curious, what is it? ;)

PS. You'll find a live, testable example here.

F A T
Admin
fat commented

This is just an incomplete implementation is all. Really if you were going to support this - you should support full navigation (with history, clicking the back and forward buttons, etc.) That requires listening to hash change events and it get's pretty rough.

David Larlet

I got this use-case too: 3 forms in 3 different tabs, I want to be able to display the right tab on user submission if there are errors on the filled form. If I remember correctly the tabs plugin from jQuery UI is doing that.

Is it an option to do not support that feature for IE 7?

Taylor Boyko

I too wanted to be able to return to a specific tab on page load, particularly for server-side form validation purposes. It seems to me that the particular tab to have selected should be a component of the URL, so I execute the following javascript on page load. It checks for an anchor and highlights the relevant tab. Otherwise, it highlights the first tab.

if (window.location.hash.length > 0) {
    $('ul.nav-tabs > li > a[href="' + window.location.hash + '"]').tab('show');
} else {
    $('ul.nav-tabs > li > a:first').tab('show');
}
Matt Gates

Same here as @davidbgk

Dan Sully

I'm using the excellent History.js for this functionality with tabs. Allowing the browser's forward & back buttons to work properly.

Should all be cross-browser compatible, with the possible exception of the window.location.hash = '';

This code doesn't actually update the URL hash at all, but instead uses pushState().

Though if the user has a hash initially, it will be read and the correct tab is shown.

Don't set a 'active' tab in the HTML itself, but do so in the JS. Alternatively, you could check for a different class, etc.

No modification of Bootstrap itself required.

$(document).ready(function() {

    // Handle tabs, page reloads & browser forward/back history.
    var History = window.History;

    if (!History.enabled) {
      return false;
    }

    $(window).bind('load statechange', function () {
      var State = History.getState();
      var hash  = History.getHash();

      // Our default tab.
      if (!State.data || !State.data.tab) {
        if (hash) {
          State.data.tab = hash;
          window.location.hash = '';
        } else {
          State.data.tab = 'YOUR DEFAULT ACTIVE TAB NAME';
        }
      }

      $('ul.nav-tabs > li > a[href="#' + State.data.tab + '"]').tab('show');
    });

    $('a[data-toggle="tab"]').on('shown', function (event) {

      // Set the selected tab to be the current state. But don't update the URL.
      var url = event.target.href.split("#")[0];
      var tab = event.target.href.split("#")[1];

      var State = History.getState();

      // Don't set the state if we haven't changed tabs.
      if (State.data.tab != tab) {
        History.pushState({'tab': tab}, null, url);
      }
    });
  });
Matt Gates

I couldn't get the above code by @dsully to work by default. I had to remove that last if statement with the pushState and then everything works awesome.

Now what if we have nav tabs on different pages? For example, 5 tabs on page 1, and 4 tabs on page 2. When you visit a tab on page 1, it will get lost after visiting a tab on page 2.

Dan Sully

Ah, yes - there's a slight bug there. It should be:

if (State.data.tab != tab) { ...

You'll need to update the url as appropriate for your business logic if you have tabs split across pages.

Matt Gates

Alright last note, what about having the fade class on tabs? Removing the active class takes away the fade effect as well when switching between tabs. So the history is snappy rather than smooth when using the above code :(

Matt Gates

Your script works out of the box for multiple pages with tabs, neat !

Matt Gates

Ah here's a bug then (or maybe just a feature request?)

Dropdown tabs are not stored, likely just due to this bit:

 $('ul.nav-tabs > li > a[href="#' + State.data.tab + '"]').tab('show');
Dan Sully

You'll need to adjust for whatever your business logic is. My code is meant as an example of what one can do - and should work for the basic nav/pill tabs.

FYI, Gist of the code here: https://gist.github.com/1938283

Chip Hayner

I went a slightly different route, and used Ben Alman's hashchange plugin instead.

// Function to activate the tab
function activateTab () {
   var activeTab = $('[href=' + location.hash + ']');
   activeTab && activeTab.tab('show');      
}

// Trigger when the page loads
activateTab();

// Trigger when the hash changes (forward / back)
$(window).hashchange(function(e) {
    activateTab();
});

// Change hash when a tab changes
$('a[data-toggle="tab"], a[data-toggle="pill"]').on('shown', function (event) {
    location.href = event.target.href;
});

alvioshki

I use @chayner way - it works fine, but I have added a small change. The script is changing the hash value to the id of the tab pane therefore I have experienced page jumping to the middle when loading. So I am adding / removing a prefix to the id (a slash sign) in order to avoid that - the page loads at the top now.

function activateTab() {
    var activeTab = $('[href=' + window.location.hash.replace('/', '') + ']');
    activeTab && activeTab.tab('show');
}

$('a[data-toggle="tab"], a[data-toggle="pill"]').on('shown', function () {
    window.location.hash = '/' + $(this).attr('href').replace('#', '');
});
令狐葱

@chayner 's way works fine, but the contents will scroll to the element when clicking on one tab due to the url contains #file_upload.
And fortunately this problem by @alvioshkand he changed the hash to i#/file_upload format. That's great!

The full scripts you need to add are :

$(function(){
    // Function to activate the tab
    function activateTab() {
        var activeTab = $('[href=' + window.location.hash.replace('/', '') + ']');
        activeTab && activeTab.tab('show');
    }

    // Trigger when the page loads
    activateTab();

    // Trigger when the hash changes (forward / back)
    $(window).hashchange(function(e) {
        activateTab();
    });

    // Change hash when a tab changes
    $('a[data-toggle="tab"], a[data-toggle="pill"]').on('shown', function () {
        window.location.hash = '/' + $(this).attr('href').replace('#', '');
    }); 
});

BTW, remember to include Ben Alman's hashchange plugin.
http://benalman.com/projects/jquery-hashchange-plugin/

adibreaban

How about nested tabs? Will @jiji262 's solution still work? I managed to get the nested tabs working just by removing the > first-child selector from

.tab-content > .tab-pane {
    display: none;
}
.tab-content > .active {
    display: block;
}
Raúl Ferràs

I've been using @jiji262 and works like a charm, but I had to modify it so it works with tabs added dinamically:

$(function(){
    // Function to activate the tab
    function activateTab() {
        var activeTab = $('[href=' + window.location.hash.replace('/', '') + ']');
        activeTab && activeTab.tab('show');
    }

    // Trigger when the page loads
    activateTab();

    // Trigger when the hash changes (forward / back)
    $(window).hashchange(function(e) {
        activateTab();
    });

    // Change hash when a tab changes
    // Handle shown event using delegation 
    $(document).on('shown.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function () {
        window.location.hash = '/' + $(this).attr('href').replace('#', '');
    }); 
});
mrfosip

Thanks for this guys!
I changed it a bit to not need the hashchange plugin:

$(function(){
  // Function to activate the tab
  function activateTab() {
      var activeTab = $('[href=' + window.location.hash.replace('/', '') + ']');
      activeTab && activeTab.tab('show');
  }

  // Trigger when the page loads
  activateTab();

  // Trigger when the hash changes (forward / back)
  $(window).on('hashchange', function() {
      activateTab();
  });

  // Change hash when a tab changes
  // Handle shown event using delegation 
  $(document).on('shown.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function () {
      window.location.hash = $(this).attr('href').replace('#', '');
  }); 
});
Carey Metcalfe pR0Ps referenced this pull request in ChrisCooper/QcumberD
Open

Preserve current tab on homepage after back/forward #91

Giovanni Lovato

Now that BS 3 dropped IE 7 support, will automatic tab activation based on hash change be supported?

Chris Rebert
Admin

It's not on the roadmap at this point.

Chris Rebert
Admin

X-Ref: #2415

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 7, 2011
  1. Peter Theill

    activate tab based on url hash

    theill authored
This page is out of date. Refresh to see the latest.
Showing with 3 additions and 0 deletions.
  1. +3 −0  js/bootstrap-tabs.js
3  js/bootstrap-tabs.js
View
@@ -75,6 +75,9 @@
$(document).ready(function () {
$('body').tabs('ul[data-tabs] li > a, ul[data-pills] > li > a')
+ if (window.location.hash) {
+ $("ul[data-tabs] li > a[href='" + window.location.hash + "'], ul[data-pills] > li > a[href='" + window.location.hash + "']").click()
+ }
})
}( window.jQuery || window.ender );
Something went wrong with that request. Please try again.