During the development of the web page, it is often required to represent multiple contents within a tab control. But, like other control, AngularJS have own tab directive. But we can create a simple tab directive with the help of AngularJS.
For creating a tab directive, we first need to create a stylesheet file. For this, we first add a style file called style.css and add the following code :-
- <style>
- .leftTab {width: 200px;float: left;padding: 0 7px;}
- .leftTab li {float: left;width: 100%;}
- .leftTab li a {height: 30px;font-size: 12px;display: block;text-align: left;padding: 3px 2px;letter-spacing: 1px;}
- .leftTab li a span {line-height: 25px;}
- .leftTab li a .iconArrow {font-size: 9px;height: 10px;margin: 9px 9px 0 0;width: 10px;}
- .leftTab li .tabSelect {font-weight: 700;}
- </style>
Now, first create the angular app as below :-
- var CustomCtrlApp = angular.module('CustomCtrlApp', []);
Now,Tab control required two different directives. One for heading related purpose and another represent the contains of that particular tab. So first we create two different html file named
Tab.html and
Tabset.html as in the following:
Tabset.html
- <div>
- <div id="leftTab" class="leftTab" ng-style="BodyStyle">
- <ul ng-transclude></ul>
- </div>
- <div class="tab-content multiPage" ng-style="BodyStyle">
- <div class="tab-pane" ng-repeat="fvtab in tabs" ng-class="{active: fvtab.active}" fv-tab-content-transclude="fvtab">
- </div>
- </div>
- </div>
Tab.html
- <li ng-class="{active: active, disabled: disabled}" ng-show="visible">
- <a ng-click="select()" fv-tab-heading-transclude ng-class="{'tabSelect' : active}">
- <i class="iconArrow left fv-right"></i><span class="left">{{heading}}</span>
- </a>
- </li>
Now, add a JavaScript file named
Tab.js and write down the following code here:
- CustomCtrlApp.service('TabService', ['$rootScope', function ($rootScope) {
- var tabsetScope = null;
- var hideIndex = null;
-
- var hide = function (index) {
- var selectedTab = tabsetScope.tabs[index];
- hideIndex = null;
- tabsetScope.hideTab(selectedTab);
- }
-
- this.setTabsetScope = function (rootScope) {
- tabsetScope = rootScope;
- if (hideIndex != #ff0000) {
- hide(hideIndex);
- }
- }
-
- this.selectTab = function (index) {
- var selectedTab = tabsetScope.tabs[index];
- tabsetScope.select(selectedTab);
- hideIndex = null;
- }
-
- this.hideTab = function (index) {
- if (tabsetScope == undefined) {
- hideIndex = index;
- }
- else {
- hide(index);
- hideIndex = null;
- }
- }
-
- this.showTab = function (index) {
- hideIndex = null;
- var selectedTab = tabsetScope.tabs[index];
- tabsetScope.showTab(selectedTab);
- }
- }]);
-
- CustomCtrlApp.directive("tabset", [function ($httpservice) {
- this;
- return {
- restrict: 'EA',
- transclude: true,
- replace: true,
- scope: {
- type: '@'
- },
- templateUrl: "../HTMLTemplate/Tabset.html",
- controller: function ($scope, $element, $attrs, TabService) {
- var ctrl = this, tabs = ctrl.tabs = $scope.tabs = [];
- $scope.BodyStyle = getElementMinHeight();
-
- ctrl.select = function (selectedTab) {
- angular.forEach(tabs, function (tab) {
- if (tab.active && tab !== selectedTab) {
- tab.active = false;
- tab.visible = true;
- tab.onDeselect();
- }
- });
- selectedTab.active = true;
- selectedTab.onSelect();
- TabService.setTabsetScope(ctrl);
- };
-
- ctrl.hideTab = function (selectedTab) {
- if (selectedTab != undefined) {
- selectedTab.visible = false;
- TabService.setTabsetScope(ctrl);
- }
- };
-
- ctrl.showTab = function (selectedTab) {
- selectedTab.visible = true;
- TabService.setTabsetScope(ctrl);
- };
-
- ctrl.addTab = function addTab(tab) {
- tabs.push(tab);
-
-
- if (tabs.length === 1 && tab.active !== false) {
- tab.active = true;
- } else if (tab.active) {
- ctrl.select(tab);
- }
- else {
- tab.active = false;
- }
- };
-
- ctrl.removeTab = function removeTab(tab) {
- var index = tabs.indexOf(tab);
-
- if (tab.active && tabs.length > 1 && !destroyed) {
-
- var newActiveIndex = index == tabs.length - 1 ? index - 1 : index + 1;
- ctrl.select(tabs[newActiveIndex]);
- }
- tabs.splice(index, 1);
- };
-
- var destroyed;
- $scope.$on('$destroy', function () {
- destroyed = true;
- });
- }
- }
- }]);
-
- CustomCtrlApp.directive('TabContentTransclude', function () {
- return {
- restrict: 'A',
- require: '^tabset',
- link: function (scope, elm, attrs) {
- var tab = scope.$eval(attrs.TabContentTransclude);
-
-
-
- tab.$transcludeFn(tab.$parent, function (contents) {
- angular.forEach(contents, function (node) {
- if (isTabHeading(node)) {
-
- tab.headingElement = node;
- } else {
- elm.append(node);
- }
- });
- });
- }
- };
- function isTabHeading(node) {
- return node.tagName && (
- node.hasAttribute('tab-heading') ||
- node.hasAttribute('data-tab-heading') ||
- node.tagName.toLowerCase() === 'tab-heading' ||
- node.tagName.toLowerCase() === 'data-tab-heading'
- );
- }
- });
-
- CustomCtrlApp.directive("tab", [function ($httpservice) {
- this;
- return {
- require: '^tabset',
- restrict: 'EA',
- replace: true,
- templateUrl: "../HTMLTemplate/Tab.html",
- transclude: true,
- scope: {
- active: '=?',
- heading: '@',
- onSelect: '&select',
-
- onDeselect: '&deselect'
- },
- controller: function () {
-
- },
- compile: function (elm, attrs, transclude) {
- return function postLink(scope, elm, attrs, tabsetCtrl) {
- scope.$watch('active', function (active) {
- if (active) {
- tabsetCtrl.select(scope);
- }
- });
-
- scope.disabled = false;
- scope.visible = true;
- if (attrs.disable) {
- scope.$parent.$watch($parse(attrs.disable), function (value) {
- scope.disabled = !!value;
- });
- }
-
-
-
-
-
- if (attrs.disabled) {
- $log.warn('Use of "disabled" attribute has been deprecated, please use "disable"');
- scope.$parent.$watch($parse(attrs.disabled), function (value) {
- scope.disabled = !!value;
- });
- }
-
- scope.select = function () {
- if (!scope.disabled) {
- scope.active = true;
- }
- };
-
- tabsetCtrl.addTab(scope);
- scope.$on('$destroy', function () {
- tabsetCtrl.removeTab(scope);
- });
-
-
-
- scope.$transcludeFn = transclude;
- };
- }
- }
- }]);
-
- CustomCtrlApp.directive('TabHeadingTransclude', [function () {
- return {
- restrict: 'A',
- require: '^tab',
- link: function (scope, elm, attrs, tabCtrl) {
- scope.$watch('headingElement', function updateHeadingElement(heading) {
- if (heading) {
- elm.html('');
- elm.append(heading);
- }
- });
- }
- };
- }]);
Actually, in the above AngularJS code we use ng-transclude to fulfill the desired objective. Actually, ng-transclude is performed as a setting which actually tell angular to capture every DOM element that is placed inside the directive in the html and use where ng-transclude is used.
Now, add another html file named TabDemo.html and write down the following code:
- <!DOCTYPE html>
- <html xmlns="http://www.w3.org/1999/xhtml">
- <head>
- <title>Sample of Tab Directive Demostration</title>
- <style>
- .leftTab {width: 200px;float: left;padding: 0 7px;}
- .leftTab li {float: left;width: 100%;}
- .leftTab li a {height: 30px;font-size: 12px;display: block;text-align: left;padding: 3px 2px;letter-spacing: 1px;}
- .leftTab li a span {line-height: 25px;}
- .leftTab li a .iconArrow {font-size: 9px;height: 10px;margin: 9px 9px 0 0;width: 10px;}
- .leftTab li .tabSelect {font-weight: 700;}
- </style>
- <script src="../Scripts/angular.min.js"></script>
- <script src="../DirectiveScript/Tab.js"></script>
- </head>
-
- <body>
- <tabset>
- <tab heading="First Tab">
- This is First Tab
- </tab>
- <tab heading="Second Tab">
- This is Second Tab
- </tab>
- </tabset>
- </body>
- </html>