Tutorial on Creating tab directives In angularjs

In this tutorial, we will see how to use another important interface component, Tabs, using the $http function to load some content.

Getting ready

To accomplish this task, we will create a controller and use the get method of the $http function to retrieve the contents of a JSON file, but first, let’s create the JSON content.

We are still using the same code base of the previous example.

How to do it…

  1. Create a new JSON file and name it tab-content.json, and add the following code:
    [
        {
            "title": "Dynamic Title 1",
            "content": "Dynamic content 1"
        },
        {
            "title": "Dynamic Title 2",
            "content": "Dynamic content 2"
        }
    ]

    • A simple array with two properties, save the file in the home directory. Append the following code in the homeCtrl.js file right after the modal directive:
      .controller('BootstrapTabCtrl', function ($scope, $http) {
      
        // Added some content to Tab / can be from a JSON with $http or $resource
        $http.get('app/home/tab-content.json').
        success(function(data) {
          // Get dynamic data from JSON file
          $scope.tabs = data;
        }).
        error(function(status) {
          // if error, show status
          console.log(status);
        });
      })
    • Now, let’s add the HTML code to the home.html file, right after the modal code:
      <!-- Bootstrap Tab -->
      <div style="width:600px; margin:20px auto;">
        <div ng-controller="BootstrapTabCtrl">
          <tabset>
            <tab ng-repeat="tab in tabs" heading="{{tab.title}}" active="tab.active" disabled="tab.disabled">
            {{tab.content}}
            </tab>
          </tabset>
        </div>
      </div>

      • Following the same format as the previous example, we will now create a custom directive to extend the UI Bootstrap functionality:
        .directive('customTabs', function() {
          return {
            restrict: 'E',
            transclude: true,
            scope: {},
            controller: [ "$scope", function($scope) {
              var panes = $scope.panes = [];
        
              $scope.select = function(pane) {
                angular.forEach(panes, function(pane) {
                  pane.selected = false;
                });
                pane.selected = true;
              }
        
              this.addPane = function(pane) {
                if (panes.length == 0) $scope.select(pane);
                  panes.push(pane);
              }
        
            }],
            // Using inline template
            template:
            '<div class="tabbable">' +
              '<ul class="nav nav-tabs">' +
                '<li ng-repeat="pane in panes" ng-class="{active:pane.selected}">'+
                '<a href="" ng-click="select(pane)">{{pane.title}}</a>' +
                '</li>' +
              '</ul>' +
              '<div class="tab-content" ng-transclude></div>' +
            '</div>',
            replace: true
          };
        })
        .directive('pane', function() {
          return {
            require: '^customTabs',
            restrict: 'E',
            transclude: true,
            scope: { title: '@' },
            link: function(scope, element, attrs, tabsCtrl) {
              tabsCtrl.addPane(scope);
            },
            // Using inline template
            template:
            '<div class="tab-pane" ng-class="{active: selected}" ng-transclude>' +
            '</div>',
            replace: true
          };
        })
      • Now, we will add the HTML markup to the home.html file:
        <!-- Custom Boostrap Tab -->
        <div style="width:600px; margin:20px auto;">
          <custom-tabs>
            <pane title="Custom Tab One">
              <div>Tab One Content.</div>
            </pane>
            <pane title="Custom Tab Two">
              <div>Tab Two Content.</div>
            </pane>
            <pane title="Custom Tab Three">
              <div>Tab Three Content.</div>
            </pane>
          </custom-tabs>
        </div>

        Tip

        Note that the style tag on the HTML examples is not a good practice, but we use it just to center the example code on the screen. Please don’t do that in production, keep your CSS files in separated files.

        How it works…

        In large-scale applications, it is very common to use dynamic content to populate the interface components. Our first example demonstrates how easy it is to use this type of content, by implementing a simple Bootstrap tab directive as the following code:

        <div ng-controller="BootstrapTabCtrl">
          <tabset>
            <tab ng-repeat="tab in tabs" heading="{{tab.title}}" active="tab.active" disabled="tab.disabled">
            {{tab.content}}
            </tab>
          </tabset>
        </div>

        The $http.get ()method makes a call to an external file, in this case the tab-content.json file, to load the tab contents of the directive.

        $http.get('app/home/tab-content.json').
          success(function(data) {
            // Get dynamic data from JSON file
            $scope.tabs = data;
        
          }).
          error(function(status) {
            // if error, show status
            console.log(status);
          });

        In the second example, we created a directive and used an inline template with the inline controller.

        .directive('customTabs', function() {
          return {
            restrict: 'E',
            transclude: true,
            scope: {},
            controller: [ "$scope", function($scope) {
              var panes = $scope.panes = [];
        
              $scope.select = function(pane) {
                angular.forEach(panes, function(pane) {
                  pane.selected = false;
                });
                pane.selected = true;
              }
        
              this.addPane = function(pane) {
                if (panes.length == 0) $scope.select(pane);
                  panes.push(pane);
              }
        
            }],
            // Using inline template
            template:
            '<div class="tabbable">' +
            '<ul class="nav nav-tabs">' +
              '<li ng-repeat="pane in panes" ng-class="{active:pane.selected}">'+
              '<a href="" ng-click="select(pane)">{{pane.title}}</a>' +
              '</li>' +
            '</ul>' +
            '<div class="tab-content" ng-transclude></div>' +
            '</div>',
            replace: true
          };
        })

        Note that this directive comprises two parts: the first simulates the links behavior as tabs, and the second activates the selected panel:

        .directive('pane', function() {
          return {
            require: '^customTabs',
            restrict: 'E',
            transclude: true,
            scope: { title: '@' },
            link: function(scope, element, attrs, tabsCtrl) {
              tabsCtrl.addPane(scope);
            },
            // Using inline template
            template:
            '<div class="tab-pane" ng-class="{active: selected}" ng-transclude>' +
            '</div>',
            replace: true
          };
        })

        It is very common for a directive to be composed of one or more parts. A directive, in this case, depends on the operation of the other. They remain connected using the link property:

        link: function(scope, element, attrs, tabsCtrl) {
          tabsCtrl.addPane(scope);
        },

        There’s more…

        We can combine both examples to load external content easily using a controller and an external template in the second example, as performed in the previous examples:

        .directive('customTabs', function() {
          return {
            restrict: 'E',
            transclude: true,
            // Declaring scope: {} we using the isolate scope and we can use the directive many times in the same page
            scope: {},
            controller: customCtrl.js,
            // Using external template
            template:app/common/tabs-custom-tpl.html,
            replace: true
          };
Deven Rathore

Deven is an Entrepreneur, and Full-stack developer, Constantly learning and experiencing new things. He currently runs CodeSource.io and Dunebook.com.

Published by
Deven Rathore

Recent Posts

Flutter App Development: Essential Things You Should Know

Divided by mobile operating systems, companies have to develop their apps twice and roll them…

6 hours ago

7 Tips To Build Responsive & Dynamic Drupal Website For Your Business

For optimal user experience, consumers want responsive websites that are easy to use, multi-device friendly,…

2 days ago

OpenCart vs Magento: What You Should Choose in 2021

Users all over the world are faced with the problem of choosing a platform for…

1 week ago

Top 20 Android Open Source Projects

Reading codes and contributing to open source has been proven to be one of the…

3 weeks ago

Top 5 tools to proofread and edit essays with the help of software

Poor grammar and incorrect spelling can significantly lower the value of any literary work. Going…

6 hours ago

The Best 5 Career Advice for Web Design Students

Are you thinking of a career in web design but not sure where to start? The…

4 weeks ago