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

Are There any Similarities Between Web Design and Art?

You may be surprised at how many of the same skills are involved!  Let’s get…

12 hours ago

Tips on Increasing your organic traffic on WordPress

Introduction  As more and more people are using online services nowadays, most of the business…

1 day ago

Five Reasons You Should Start a Social Media Campaign

Small businesses need all the advertisements they can get. Traditional avenues for advertising, such as…

2 days ago

Top 10 SEO Writing Tips for Beginners 2021

Search Engine Optimization. It’s complicated, to say the least. Search engines, like Google, are constantly…

1 week ago

Should you become a freelancer in 2021? Pros and Cons

Freelancing and working from home was long considered idyllic by many, but the global pandemic…

1 week ago

The Leading Renewable Energy Trends in 2021

The past year saw slowdowns in the ongoing shift toward renewable energy in many countries…

2 weeks ago