Dynamically Loading Content in Twitter Bootstrap Tabs

Achtung! This is an old post, written before Bootstrap was in 2.0. The current version of Bootstrap is 3. You probably do not want to use this. The general idea is still the same though. I highly recommend reading Jake Spurlock's book on Bootstrap and the Bootstrap documentation instead, and use the basic principles of this post to figure it out on your own.
So, today's blog will be slightly off the norm. I had been working on a project for some time, and over the weekend, we had decided to port it over to the very excellent Twitter Bootstrap from JQueryUI. With a new framework, comes new learnings. You see, in JQueryUI Tabs, you could dynamically load your tab content with this:

<div id="example">
     <ul>
         <li><a href="ahah_1.html"><span>Content 1</span></a></li>
         <li><a href="ahah_2.html"><span>Content 2</span></a></li>
         <li><a href="ahah_3.html"><span>Content 3</span></a></li>
     </ul>
</div>
There is no way to do so in Twitter Bootstrap. At least not easily anyway. So I hacked around for a bit. And together with Ruben, we came up with a quick and easy solution. This is the default way to do tabs in Twitter Bootstrap:
<ul class="tabs">
    <li class="active"><a href="#home">Home</a></li>
    <li><a href="#profile">Profile</a></li>
    <li><a href="#messages">Messages</a></li>
    <li><a href="#settings">Settings</a></li>
</ul>
 
<div class="pill-content">
    <div class="active" id="home">...</div>
    <div id="profile">...</div>
    <div id="messages">...</div>
    <div id="settings">...</div>
</div>
 
<script>
    $(function () {
        $('.tabs').tabs()
    })
</script>

You can use e.target and e.relatedTarget to get your active tab and previous tab objects. I messed around for a bit withe.target and e.relatedTarget, and found out that e.target.toString() returns http://____/#targetAnchor.

The Code

With that insight, I hacked around my code to get what I wanted - a JQueryUI-like dynamic loading of content of tabs. True to what a statistician does, I use regex and string manipulation to make tabs load pages when it is actie. It's nothing revolutionary, I didn't patch Twitter Bootstrap - it was just to get my project working (in all browsers except IE. FML). The reason why I am positing this is because I tried looking for an example to do this, but couldn't find one. Hope this finds you. This code below is used in the last bit of the page, when everything is ready and loaded, to initialize all the things.
<script>
  $(document).ready(function() {
    $('#tab1').load('/tab1Content', function() {
      $('.tabs').tabs(); //reinitialize tabs
    });

    $('.tabs').bind('change', function(e) {
      var pattern=/#.+/gi //set a regex pattern (all the things after "#").
      var contentID = e.target.toString().match(pattern)[0]; //find pattern

      $(contentID).load('/'+contentID.replace('#',''), function(){
        $('.tabs').tabs(); //reinitialize tabs
      });
    }); 
  });
</script>

Notes

Somethings to note:
  • JQuery is obviously required
  • '#tab1' is the id of pill-content (look at 2nd codebox)
  • '/tab1Content' is the location of where your content will be
  • The targetAnchor must be the same or similar to your location (mine was: #list and /list). Feel free to play around
There are a few caveats to this code. The regular expression used was terrible. You see, my e.target.toString() returns http://localhost/#targetAnchor. And I knew that I don't have URLs like http://localhost/#targetAnchor/somethingElse so I can rather confidently use that regex. I would recommend you write your own regex.

Thoughts

I had grumbled at first, when I found out that Bootstrap couldn't do what JQueryUI Tabs did out of the box, but in retrospect, I found it more flexible. For example, it would be very easy for me to have 3 tabs, Tab1, Tab2, Tab3, where Tab1 loads content off the page, while Tabs 2 and 3 did AJAX calls to load content. As a guy who don't know much Javascript programming beyond the basics, Bootstrap is easy to use. Tell me what you think? If anyone spots a problem, feel free to comment and tell me where it all went wrong
comments powered by Disqus