Skip to content
This repository was archived by the owner on May 29, 2019. It is now read-only.

Commit 42ab60b

Browse files
committed
refactor(tab): change to use centralized active state
- Change to store active index on tabset controller - Set index on tab by tab basis BREAKING CHANGE: The tab API is changed - please refer to the documentation on new usage of tabs
1 parent 10eac7c commit 42ab60b

File tree

6 files changed

+234
-176
lines changed

6 files changed

+234
-176
lines changed

misc/demo/index.html

+3-3
Original file line numberDiff line numberDiff line change
@@ -233,13 +233,13 @@ <h1><%= module.displayName %><small>
233233
<div class="pull-right">
234234
<button type="button" class="btn btn-info plunk-btn" ng-click="edit('<%= ngversion%>', '<%= bsversion %>', '<%= pkg.version%>', '<%= module.name %>')"><i class="glyphicon glyphicon-edit"></i> Edit in plunker</button>
235235
</div>
236-
<uib-tabset>
237-
<uib-tab heading="Markup">
236+
<uib-tabset active="activeTab">
237+
<uib-tab index="0" heading="Markup">
238238
<div plunker-content="markup">
239239
<pre ng-non-bindable><code data-language="html"><%- module.docs.html %></code></pre>
240240
</div>
241241
</uib-tab>
242-
<uib-tab heading="JavaScript">
242+
<uib-tab index="1" heading="JavaScript">
243243
<div plunker-content="javascript">
244244
<pre ng-non-bindable><code data-language="javascript"><%- module.docs.js %></code></pre>
245245
</div>

src/tabs/docs/demo.html

+17-17
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,20 @@
77
<div ng-controller="TabsDemoCtrl">
88
<p>Select a tab by setting active binding to true:</p>
99
<p>
10-
<button type="button" class="btn btn-default btn-sm" ng-click="tabs[0].active = true">Select second tab</button>
11-
<button type="button" class="btn btn-default btn-sm" ng-click="tabs[1].active = true">Select third tab</button>
10+
<button type="button" class="btn btn-default btn-sm" ng-click="scope.active = 1">Select second tab</button>
11+
<button type="button" class="btn btn-default btn-sm" ng-click="scope.active = 2">Select third tab</button>
1212
</p>
1313
<p>
1414
<button type="button" class="btn btn-default btn-sm" ng-click="tabs[1].disabled = ! tabs[1].disabled">Enable / Disable third tab</button>
1515
</p>
1616
<hr />
1717

18-
<uib-tabset>
19-
<uib-tab heading="Static title">Static content</uib-tab>
20-
<uib-tab ng-repeat="tab in tabs" heading="{{tab.title}}" active="tab.active" disable="tab.disabled">
18+
<uib-tabset active="active">
19+
<uib-tab index="0" heading="Static title">Static content</uib-tab>
20+
<uib-tab index="$index + 1" ng-repeat="tab in tabs" heading="{{tab.title}}" active="tab.active" disable="tab.disabled">
2121
{{tab.content}}
2222
</uib-tab>
23-
<uib-tab select="alertMe()">
23+
<uib-tab index="3" select="alertMe()">
2424
<uib-tab-heading>
2525
<i class="glyphicon glyphicon-bell"></i> Alert!
2626
</uib-tab-heading>
@@ -30,36 +30,36 @@
3030

3131
<hr />
3232

33-
<uib-tabset vertical="true" type="pills">
34-
<uib-tab heading="Vertical 1">Vertical content 1</uib-tab>
35-
<uib-tab heading="Vertical 2">Vertical content 2</uib-tab>
33+
<uib-tabset active="activePill" vertical="true" type="pills">
34+
<uib-tab index="0" heading="Vertical 1">Vertical content 1</uib-tab>
35+
<uib-tab index="1" heading="Vertical 2">Vertical content 2</uib-tab>
3636
</uib-tabset>
3737

3838
<hr />
3939

40-
<uib-tabset justified="true">
41-
<uib-tab heading="Justified">Justified content</uib-tab>
42-
<uib-tab heading="SJ">Short Labeled Justified content</uib-tab>
43-
<uib-tab heading="Long Justified">Long Labeled Justified content</uib-tab>
40+
<uib-tabset active="activeJustified" justified="true">
41+
<uib-tab index="0" heading="Justified">Justified content</uib-tab>
42+
<uib-tab index="1" heading="SJ">Short Labeled Justified content</uib-tab>
43+
<uib-tab index="2" heading="Long Justified">Long Labeled Justified content</uib-tab>
4444
</uib-tabset>
4545

4646
<hr />
4747

4848
Tabs using nested forms:
4949
<form name="outerForm" class="tab-form-demo">
50-
<uib-tabset>
51-
<uib-tab heading="Form Tab">
50+
<uib-tabset active="activeForm">
51+
<uib-tab index="0" heading="Form Tab">
5252
<ng-form name="nestedForm">
5353
<div class="form-group">
5454
<label>Name</label>
5555
<input type="text" class="form-control" required ng-model="model.name"/>
5656
</div>
5757
</ng-form>
5858
</uib-tab>
59-
<uib-tab heading="Tab One">
59+
<uib-tab index="1" heading="Tab One">
6060
Some Tab Content
6161
</uib-tab>
62-
<uib-tab heading="Tab Two">
62+
<uib-tab index="2" heading="Tab Two">
6363
More Tab Content
6464
</uib-tab>
6565
</uib-tabset>

src/tabs/docs/readme.md

+8
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ AngularJS version of the tabs directive.
22

33
### uib-tabset settings
44

5+
* `active`
6+
<small class="badge">$</small>
7+
_(Default: Index of first tab)_
8+
Active index of tab.
9+
510
* `justified`
611
<small class="badge">$</small>
712
_(Default: `false`)_ -
@@ -37,6 +42,9 @@ AngularJS version of the tabs directive.
3742
* `heading` -
3843
Heading text.
3944

45+
* `index` -
46+
Tab index
47+
4048
* `select()`
4149
<small class="badge">$</small> -
4250
An optional expression called when tab is activated.

src/tabs/tabs.js

+81-42
Original file line numberDiff line numberDiff line change
@@ -2,66 +2,103 @@ angular.module('ui.bootstrap.tabs', [])
22

33
.controller('UibTabsetController', ['$scope', function ($scope) {
44
var ctrl = this,
5-
tabs = ctrl.tabs = $scope.tabs = [];
6-
7-
ctrl.select = function(selectedTab) {
8-
angular.forEach(tabs, function(tab) {
9-
if (tab.active && tab !== selectedTab) {
10-
tab.active = false;
11-
tab.onDeselect();
12-
selectedTab.selectCalled = false;
5+
oldIndex;
6+
ctrl.tabs = [];
7+
8+
ctrl.select = function(index) {
9+
if (!destroyed) {
10+
var previousIndex = findTabIndex(oldIndex);
11+
var previousSelected = ctrl.tabs[previousIndex];
12+
if (previousSelected) {
13+
previousSelected.tab.onDeselect();
14+
previousSelected.tab.active = false;
15+
}
16+
17+
var selected = ctrl.tabs[index];
18+
if (selected) {
19+
selected.tab.onSelect();
20+
selected.tab.active = true;
21+
ctrl.active = selected.index;
22+
oldIndex = selected.index;
23+
} else if (!selected && angular.isNumber(oldIndex)) {
24+
ctrl.active = null;
25+
oldIndex = null;
1326
}
14-
});
15-
selectedTab.active = true;
16-
// only call select if it has not already been called
17-
if (!selectedTab.selectCalled) {
18-
selectedTab.onSelect();
19-
selectedTab.selectCalled = true;
2027
}
2128
};
2229

2330
ctrl.addTab = function addTab(tab) {
24-
tabs.push(tab);
25-
// we can't run the select function on the first tab
26-
// since that would select it twice
27-
if (tabs.length === 1 && tab.active !== false) {
28-
tab.active = true;
29-
} else if (tab.active) {
30-
ctrl.select(tab);
31-
} else {
32-
tab.active = false;
31+
ctrl.tabs.push({
32+
tab: tab,
33+
index: tab.index
34+
});
35+
ctrl.tabs.sort(function(t1, t2) {
36+
if (t1.index > t2.index) {
37+
return 1;
38+
}
39+
40+
if (t1.index < t2.index) {
41+
return -1;
42+
}
43+
44+
return 0;
45+
});
46+
47+
if (tab.index === ctrl.active || !angular.isNumber(ctrl.active) && ctrl.tabs.length === 1) {
48+
var newActiveIndex = findTabIndex(tab.index);
49+
ctrl.select(newActiveIndex);
3350
}
3451
};
3552

3653
ctrl.removeTab = function removeTab(tab) {
37-
var index = tabs.indexOf(tab);
38-
//Select a new tab if the tab to be removed is selected and not destroyed
39-
if (tab.active && tabs.length > 1 && !destroyed) {
40-
//If this is the last tab, select the previous tab. else, the next tab.
41-
var newActiveIndex = index === tabs.length - 1 ? index - 1 : index + 1;
42-
ctrl.select(tabs[newActiveIndex]);
54+
var index = findTabIndex(tab.index);
55+
56+
if (tab.index === ctrl.active) {
57+
var newActiveTabIndex = index === ctrl.tabs.length - 1 ?
58+
index - 1 : index + 1 % ctrl.tabs.length;
59+
ctrl.select(newActiveTabIndex);
4360
}
44-
tabs.splice(index, 1);
61+
62+
ctrl.tabs.splice(index, 1);
4563
};
4664

65+
$scope.$watch('tabset.active', function(val) {
66+
if (angular.isNumber(val) && val !== oldIndex) {
67+
ctrl.select(findTabIndex(val));
68+
}
69+
});
70+
4771
var destroyed;
4872
$scope.$on('$destroy', function() {
4973
destroyed = true;
5074
});
75+
76+
function findTabIndex(index) {
77+
for (var i = 0; i < ctrl.tabs.length; i++) {
78+
if (ctrl.tabs[i].index === index) {
79+
return i;
80+
}
81+
}
82+
}
5183
}])
5284

5385
.directive('uibTabset', function() {
5486
return {
5587
transclude: true,
5688
replace: true,
57-
scope: {
89+
scope: {},
90+
bindToController: {
91+
active: '=',
5892
type: '@'
5993
},
6094
controller: 'UibTabsetController',
95+
controllerAs: 'tabset',
6196
templateUrl: 'uib/template/tabs/tabset.html',
6297
link: function(scope, element, attrs) {
63-
scope.vertical = angular.isDefined(attrs.vertical) ? scope.$parent.$eval(attrs.vertical) : false;
64-
scope.justified = angular.isDefined(attrs.justified) ? scope.$parent.$eval(attrs.justified) : false;
98+
scope.vertical = angular.isDefined(attrs.vertical) ?
99+
scope.$parent.$eval(attrs.vertical) : false;
100+
scope.justified = angular.isDefined(attrs.justified) ?
101+
scope.$parent.$eval(attrs.justified) : false;
65102
}
66103
};
67104
})
@@ -73,8 +110,8 @@ angular.module('ui.bootstrap.tabs', [])
73110
templateUrl: 'uib/template/tabs/tab.html',
74111
transclude: true,
75112
scope: {
76-
active: '=?',
77113
heading: '@',
114+
index: '=',
78115
onSelect: '&select', //This callback is called in contentHeadingTransclude
79116
//once it inserts the tab's content into the dom
80117
onDeselect: '&deselect'
@@ -84,12 +121,6 @@ angular.module('ui.bootstrap.tabs', [])
84121
},
85122
controllerAs: 'tab',
86123
link: function(scope, elm, attrs, tabsetCtrl, transclude) {
87-
scope.$watch('active', function(active) {
88-
if (active) {
89-
tabsetCtrl.select(scope);
90-
}
91-
});
92-
93124
scope.disabled = false;
94125
if (attrs.disable) {
95126
scope.$parent.$watch($parse(attrs.disable), function(value) {
@@ -99,7 +130,15 @@ angular.module('ui.bootstrap.tabs', [])
99130

100131
scope.select = function() {
101132
if (!scope.disabled) {
102-
scope.active = true;
133+
var index;
134+
for (var i = 0; i < tabsetCtrl.tabs.length; i++) {
135+
if (tabsetCtrl.tabs[i].tab === scope) {
136+
index = i;
137+
break;
138+
}
139+
}
140+
141+
tabsetCtrl.select(index);
103142
}
104143
};
105144

@@ -135,7 +174,7 @@ angular.module('ui.bootstrap.tabs', [])
135174
restrict: 'A',
136175
require: '^uibTabset',
137176
link: function(scope, elm, attrs) {
138-
var tab = scope.$eval(attrs.uibTabContentTransclude);
177+
var tab = scope.$eval(attrs.uibTabContentTransclude).tab;
139178

140179
//Now our tab is ready to be transcluded: both the tab heading area
141180
//and the tab content area are loaded. Transclude 'em both.

0 commit comments

Comments
 (0)