Browser like tabs with angularjs and bootstrap

May 4, 2015
by Rahil Shaikh

AngularJs is what html would have had been if it was to build dynamic web applications. In this lesson we will take Bootstrap’s tab component and make it dynamic using angularjs and build browser like tabs.

This will be a comprehensive and simple tutorial and only requires you to have a basic knowledge of Bootstrap and AngularJs.

Features

Included

  • Add a new tab
  • Close a tab
  • Select a tab

Excluded

  • Dragging a tab
  • Automatic resizing

DEMO  DOWNLOAD

Set up HTML

Include Bootstrap css and angularjs.You can download the Bootstrap bundle from here. Also include style.css and app.js, we will bulild them as we go along this tutorial.
As you can see we are using Boottraps tabpanel. Bellow there is only one tab and a content section.
If you run the below code you’ll find a static tabpanel with a tab as Home.

index.html
<!DOCTYPE html>
<html>
    <head>
        <link href="css/bootstrap.min.css" rel="stylesheet" media="screen" />
        <link href="css/bootstrap-theme.min.css" rel="stylesheet" media="screen"/>
                <link href="css/style.css" rel="stylesheet" media="screen" />
    </head>
<body>
        <div role="tabpanel">
            <ul class="nav nav-tabs" role="tablist">
                <li role="presentation"><a data-target="#tab" aria-controls="home" role="tab" data-toggle="tab">Home</a></li>
            </ul>
            <div class="tab-content">
                <div role="tabpanel" class="tab-pane active" id="tab">
                   
                </div>
            </div>
        </div>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.js"></script></script>
        <script src="js/app.js"></script>
</body>
</html>
Setting up angular app

Next we setup the skeleton for our Angular app in app.js. We have declared an angular module as tabDemo.
We have a controller named tabCtrl.

$scope.tabs is an array of objects that holds the information on tabs. We will be looping over this array using ng-repeat. As of now it holds only one object, this will be the default tab on load.

We have defined two functions $scope.addTab() and $scope.deleteTab() for adding and removing tabs respectively, we will write the functionality for them further in this post.

app.js
(function(){
    angular.module('tabDemo',[])

    .controller('tabCtrl',['$scope',function($scope){
        /** holds tabs, we will perform repeat on this **/
        $scope.tabs = [{
            id:0,
            content:'This is a default tab on load'
        }]
       
        /** Function to add a new tab **/
        $scope.addTab = function(){
       
        }
       
        /** Function to delete a tab **/
        $scope.deleteTab = function(){
       
        }
    }])
})()
Adding a new tab

First we repeat the li element on $scope.tabs.To do this add ng-repeat="tab in tabs on li element inside ‘nav-tabs’.
Next we add one more static li element as our add tab button in our markup. We call addTab() function on ng-click.

index.html
                      <ul class="nav nav-tabs" role="tablist">
                <li role="presentation" ng-repeat="tab in tabs"> <!-- repeat on tabs -->
                    <a data-target="#tab" aria-controls="home" role="tab" data-toggle="tab">Home</a>
                </li>
                <li role="presentation" ng-click="addTab()"> <!-- add tab hook -->
                    <a aria-controls="home" role="tab" data-toggle="tab">( + )</a>
                </li>
            </ul>

To keep track of the tabs selected and added we will define a counter that starts from 1 and and every time a tab is added we increment it by one and then assign the counter value to the ‘id’ key of that object of the $scope.tabs array.

$scope.addTab() function increments the counter by one and pushes a new object(ie a new tab) into the $scope.tabs array.

app.js
    $scope.counter = 1;
        /** Function to add a new tab **/
        $scope.addTab = function(){
            $scope.counter++;
            $scope.tabs.push({id:$scope.counter,content:'Any Content'});           
        }
Select tab on click

Now that we can add new tabs dynamically, we have to allow user to select different tabs and display relavent content depending on the tab selected.

‘ng-repeat’ of AngularJs provides us with an ‘$index’ variable that holds the offset of the element starting from 0.
As we are repeating over an array it will also represent the index of the array.

Now we define a variable as $scope.selectedTab which defaults to 0. We assign it the value of ‘$index’ of the tab clicked on.
To do this we create a function in our controller $scope.selectTab($index) and then call the function on click of any tab, passing ‘$index’ as a parameter, using ‘ng-click’ and then assigning $scope.selectedTab = $index.

Then using ng-class we will set the clicked element to active by adding .active class provided by Bootstrap.

Add the below code to the repeating element.
ng-click="selectTab($index)" ng-class="{'active':selectedTab == $index}"

We will show the id and content of the selected tab using tabs[selectedTab].id and tabs[selectedTab].content. selectedTab is the index of the tabs array ofcourse.

index.html
.....
...
<li role="presentation" ng-repeat="tab in tabs" ng-click="selectTab($index)" ng-class="{'active':selectedTab == $index}">
                    <a data-target="#tab" aria-controls="home" role="tab" data-toggle="tab">Tab {{tab.id}}</a>
                </li>
...
.....
<div class="tab-content">
                <div role="tabpanel" class="tab-pane active" id="tab">
                    <h1>Tab {{tabs[selectedTab].id}}</h1>
                    <h3>Content:- {{tabs[selectedTab].content}}</h3>
                </div>
            </div>

Adding $scope.selectTab() function to our controller.

app.js
...
..
$scope.selectedTab = 0; //set selected tab to the 1st by default.
       
        /** Function to set selectedTab **/
        $scope.selectTab = function(index){
            $scope.selectedTab = index;
        }
..
...
Closing a tab

Using Bootstarp’s glyphicons we will add a close icon to our tabs and on click of it we will call $scope.deleteTab($index) function passing $index as a parameter, using ‘ng-click’.

index.html
....
..
<li role="presentation" ng-repeat="tab in tabs" ng-click="selectTab($index)" ng-class="{'active':selectedTab == $index}">
                    <a data-target="#tab" aria-controls="home" role="tab" data-toggle="tab">Tab {{tab.id}} <span ng-click="deleteTab($index)" class="glyphicon glyphicon-remove"></span></a>
                </li>
....
...

This is what our deleteTab function looks like. We just remove the object on that index.

app.js
....
.....
/** Function to delete a tab **/
        $scope.deleteTab = function(index){
            $scope.tabs.splice(index,1); //remove the object from the array based on index
        }
...
..

One more thing we need to do is when ever we add a new tab that tab should get active immediately, as it happens for browsers.

To do that, we need to set the $scope.selectedTab variable to the length of the $scope.tabs array minus one.
So now our $scope.addTab() function will look like this.

app.js
...
...
/** Function to add a new tab **/
        $scope.addTab = function(){
            $scope.counter++;
            $scope.tabs.push({id:$scope.counter,content:'Any Content'});
            $scope.selectedTab = $scope.tabs.length - 1; //set the newly added tab active.
        }
...
....
Finally some css
style.css
.nav-tabs > li > a{
    cursor:pointer;
}

.nav-tabs li a span:hover {
    color: red;
    cursor:pointer;
}
app.js and index.html after completion
index.html
<!DOCTYPE html>
<html>
    <head> 
        <link href="css/bootstrap.min.css" rel="stylesheet" media="screen" />
        <link href="css/bootstrap-theme.min.css" rel="stylesheet" media="screen"/>
        <link href="css/style.css" rel="stylesheet" media="screen"/>
    </head>
    <body ng-app="tabDemo">
        <div role="tabpanel" ng-controller="tabCtrl">
            <ul class="nav nav-tabs" role="tablist">
                <li role="presentation" ng-repeat="tab in tabs" ng-click="selectTab($index)" ng-class="{'active':selectedTab == $index}">
                    <a data-target="#tab" aria-controls="home" role="tab" data-toggle="tab">Tab {{tab.id}} <span ng-click="deleteTab($index)" class="glyphicon glyphicon-remove"></span></a>
                </li>
                <li role="presentation" ng-click="addTab()">
                    <a aria-controls="home" role="tab" data-toggle="tab">( + )</a>
                </li>
            </ul>
            <div class="tab-content">
                <div role="tabpanel" class="tab-pane active" id="tab">
                    <h1>Tab {{tabs[selectedTab].id}}</h1>
                    <h3>Content:- {{tabs[selectedTab].content}}</h3>
                </div>
            </div>
        </div>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular.js"></script>
        <script src="js/app.js"></script>
    </body>
</html>
app.js
(function(){
    angular.module('tabDemo',[])

    .controller('tabCtrl',['$scope',function($scope){
        /** holds tabs, we will perform repeat on this **/
        $scope.tabs = [{
            id:1,
            content:'This is a default tab on load'
        }]
       
        $scope.counter = 1;
        /** Function to add a new tab **/
        $scope.addTab = function(){
            $scope.counter++;
            $scope.tabs.push({id:$scope.counter,content:'Any Content'});
            $scope.selectedTab = $scope.tabs.length - 1; //set the newly added tab active.
        }
       
        /** Function to delete a tab **/
        $scope.deleteTab = function(index){
            $scope.tabs.splice(index,1); //remove the object from the array based on index
        }
       
        $scope.selectedTab = 0; //set selected tab to the 1st by default.
       
        /** Function to set selectedTab **/
        $scope.selectTab = function(index){
            $scope.selectedTab = index;
        }
    }])
})()

DEMO  DOWNLOAD

Conclusion

Tabs improve the layout of your application and make it user friendly. Bootstrap provides us with a nice layout for static tabs, but using the power of AngularJs we can make them dynamic and build browser like, dynamic tabs, as we did in this tutorial.

Go ahead and try this in your future projects.

About

Engineer. Blogger. Thinker. Loves programming and working with emerging tech. We can also talk on Football, Gaming, World Politics, Monetary Systems.

Free PDF

Subscribe and get AngularJS Tips PDF. We never spam!
First Name:
Email:

6 comments

  1. |

    How to load content in that new tabs

    • deepak
      |

      I want to tab after sidebar menu click in body of the page..and show multiple tab in body ..please help me

  2. anu
    |

    tutorial is good but when closing tab memory is not decreasing can you provide solution for it?

    • |

      I did not get your point on decreasing tab memory.

  3. shan
    |

    If we want to have dynamic content in the tab content like, have 2 text boxes and accept data… how can we achieve that?

    • |

      You can try ng-bind-html.
      There may be other ways to do it, try to dig in and solve it, also let me know the solution.
      Right now I’m short of time else wold have done it myself.

Leave a Comment