1

how to write a service or factory for bootstrap tabs using angularJs. I placed in one controller but need a common function(repeated code) for different controllers.

<ul class="nav nav-tabs">
    <li data-ng-class="{active:tab===0}">
        <a href ng-click="changeTab(0)"> <i class="fa fa-list"></i></a>
    </li>
    <li data-ng-class="{active:tab===1}">
        <a href ng-click="changeTab(1)"><i class="fa fa-user"></i></a>
    </li>
</ul>

<div data-ng-class="{activeTab:tab===0}" ng-show="isActiveTab(0)">
  tab1
</div>
<div data-ng-class="{activeTab:tab===1}" ng-show="isActiveTab(1)">
  tab2
</div>

controller

$scope.tab = 0;    
    $scope.changeTab = function(newTab){
      $scope.tab = newTab;
    };    
    $scope.isActiveTab = function(tab){
      return $scope.tab === tab;
    }; 
vishnu
  • 4,377
  • 15
  • 52
  • 89

3 Answers3

4

Managing tabs is a view concern. Rather than implementing a factory, I recommend creating two directives: tabContainer and tab. The tab directive registers itself with the parent tabContainer using the require attribute to access the parent directive's controller API.

Demo

Usage

<tab-container selected="tab2">
   <tab name="tab1">tab1</tab>
   <tab name="tab2">tab2</tab>
</tab-container>

Parent Directive

The parent directive publishes the following controller API that the child tab directives will access:

tabContainer controller

// registers this tab with the parent tabContainer
this.register = function(element) {
  $scope.tabs.push(element);
}
// returns the selected tab object whose 
// name property indicates which tab is active
this.getSelected = function() {
  return $scope.selectedTab;
}

Child Directive

The tab directive is able to access the parent controller by requiring the parent directive in its directive definition, and accessing the parent directive's controller as the 4th argument to the tab directive's link function:

tab directive definition

scope: true,
require: '^tabContainer',
link: function(scope, element, attr, tabContainer) {
  // set the tab so that it is visible in the tab directive's scope.
  scope.tab = { name: attr.name, element:element};
  scope.selectedTab = tabContainer.getSelected();
  tabContainer.register(scope.tab);

}

The scope is set to true so that each tab will create its own child scope and not interfere with the scope of other tabs.

Template Files

For example purposes, the directive templates are embedded in the HTML:

<script type="text/ng-template" id="tabContainer.html">
  <ul class="nav nav-tabs">
    <li ng-repeat="tab in tabs" data-ng-class="{active:selectedTab.name===tab.name}">
      <a href ng-click="changeTab(tab)"> <i class="fa fa-list">{{tab.name}}</i></a>
    </li>
  </ul>
  <ng-transclude></ng-transclude>
</script>
<script type="text/ng-template" id="tab.html">
 <div data-ng-class="{activeTab:selectedTab.name===tab.name}" ng-show="selectedTab.name === tab.name">
     <ng-transclude></ng-transclude>
 </div>
</script>

It is recommended to move these to dedicated HTML files.

Changing the Active Tab

The user is able to change the active tab by clicking the tab link. This is achieved by publishing a $scope function in the parent controller:

$scope.changeTab = function(tab) {
  $scope.selectedTab.name = tab.name;
}

Creating a Tabs Module

The beauty of AngularJS and its pluggable modular architecture is that you can extend the AngularJS directive ecosystem, and have the directives work together seamlessly. For example, you could encapsulate the above tabs directive into a tabs module, and even use the ngRepeat directive to bind the tabs.

Demo

Controller

var app = angular.module('app',['tabs']);
app.controller('ctrl', function($scope) {
   $scope.tabData = [ 
      { name: 'tab1', body: 'You selected tab1!'},
      { name: 'tab2', body: 'You selected tab2!'},
      { name: 'tab3', body: 'You selected tab3!'},
      { name: 'tab4', body: 'You selected tab4!'},
    ];
});

View

<div class="container" ng-controller="ctrl">
   <tab-container selected="tab1">
     <tab ng-repeat="tab in tabData" name="{{tab.name}}">{{ tab.body }} </tab>
  </tab-container>
</div>
Michael Kang
  • 52,003
  • 16
  • 103
  • 135
1

Hi I write it with out using any service or factory see the example

<ul ng-init="tab = 1">          
    <li ng-class="{active:tab===1}"> 
      <a href ng-click="tab = 1">Tab1</a>               
    </li>           
    <li ng-class="{active:tab===2}"> 
       <a href ng-click="tab = 2">Tab2</a>              
    </li>           
    <li ng-class="{active:tab===3}"> 
      <a href ng-click="tab = 3">Tab3</a>           
    </li>           
    <br><br> 
    <p ng-show="tab === 1"> Tab1 content </p>           
    <p ng-show="tab === 2"> Tab2 content</p> 
    <p ng-show="tab === 3"> Tab3 content</p>        
</ul>

Dynamically change it through controller see the working example here

vamsikrishnamannem
  • 4,817
  • 5
  • 23
  • 34
1

The structure for controllers/services in Angular are explained well here: https://github.com/johnpapa/angular-styleguide

In app.js, we declare an angular application, give it a name, and any dependencies (ng-route / ng-grid). $http calls should be made using a factory or a service, and the controller should call the service to fetch or post data. From the angular documentation, "services are substitutable objects that are wired together using dependency injection (DI). You can use services to organize and share code across your app." https://docs.angularjs.org/guide/services

app.js:

var app = angular.module('appname', []);

app.factory('httpResponseErrorInterceptor'...
app.config(['$httpProvider',...

Controller:

    angular.module('appname').controller("NameCtrl", ["$scope", "$log", "$window", "$http", "$timeout", "SomeService",
    function ($scope, $log, $window, $http, $timeout, TabService) {

    //your controller code
       $scope.tab = 0;    
       $scope.changeTab = function(newTab){
          $scope.tab = newTab;
       };    
       $scope.isActiveTab = function(tab){
          return $scope.tab === tab;
       }; 
    }
]);

Service:

angular.module('appname').service("TabService", function () {
   //Your code for shared functionality regarding tab service

   var currentTab = {};

   return {
      currentTab : currentTab 
   }
});
Boris
  • 566
  • 5
  • 21