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

Commit 2b78dd1

Browse files
committed
feat(tabs): support disabled state
1 parent c690b83 commit 2b78dd1

File tree

6 files changed

+100
-13
lines changed

6 files changed

+100
-13
lines changed

src/tabs/docs/demo.html

+6-8
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
<div ng-controller="TabsDemoCtrl">
22
Select a tab by setting active binding to true:
33
<br />
4-
<button class="btn" ng-click="tabs[0].active = true">
5-
Select second tab
6-
</button>
7-
<button class="btn" ng-click="tabs[1].active = true">
8-
Select third tab
9-
</button>
10-
<br /><br />
4+
<button class="btn btn-small" ng-click="tabs[0].active = true">Select second tab</button>
5+
<button class="btn btn-small" ng-click="tabs[1].active = true">Select third tab</button>
6+
<button class="btn btn-small" ng-click="tabs[1].disabled = ! tabs[1].disabled">Enable / Disable third tab</button>
7+
<hr />
8+
119
<tabset>
1210
<tab heading="Static title">Static content</tab>
13-
<tab ng-repeat="tab in tabs" heading="{{tab.title}}" active="tab.active">
11+
<tab ng-repeat="tab in tabs" heading="{{tab.title}}" active="tab.active" disabled="tab.disabled">
1412
{{tab.content}}
1513
</tab>
1614
<tab select="alertMe()">

src/tabs/docs/demo.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
var TabsDemoCtrl = function ($scope) {
22
$scope.tabs = [
33
{ title:"Dynamic Title 1", content:"Dynamic content 1" },
4-
{ title:"Dynamic Title 2", content:"Dynamic content 2" }
4+
{ title:"Dynamic Title 2", content:"Dynamic content 2", disabled: true }
55
];
66

77
$scope.alertMe = function() {

src/tabs/docs/readme.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
AngularJS version of the tabs directive.
22

3-
Allows a `select` callback attribute, and `active` binding attribute.
3+
Allows a `select` callback attribute, `active` binding attribute and `disabled` binding attribute.
44

55
Allows either `heading` text-heading as an attribute, or a `<tab-heading>` element inside as the heading.

src/tabs/tabs.js

+15-2
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,11 @@ function($parse, $http, $templateCache, $compile) {
7171
getActive = $parse(attrs.active);
7272
setActive = getActive.assign;
7373
scope.$parent.$watch(getActive, function updateActive(value) {
74-
scope.active = !!value;
74+
if ( !!value && scope.disabled ) {
75+
setActive(scope.$parent, false); // Prevent active assignment
76+
} else {
77+
scope.active = !!value;
78+
}
7579
});
7680
} else {
7781
setActive = getActive = angular.noop;
@@ -85,8 +89,17 @@ function($parse, $http, $templateCache, $compile) {
8589
}
8690
});
8791

92+
scope.disabled = false;
93+
if ( attrs.disabled ) {
94+
scope.$parent.$watch($parse(attrs.disabled), function(value) {
95+
scope.disabled = !! value;
96+
});
97+
}
98+
8899
scope.select = function() {
89-
scope.active = true;
100+
if ( ! scope.disabled ) {
101+
scope.active = true;
102+
}
90103
};
91104

92105
tabsetCtrl.addTab(scope);

src/tabs/test/tabsSpec.js

+76
Original file line numberDiff line numberDiff line change
@@ -378,4 +378,80 @@ describe('tabs', function() {
378378
expect(contents().eq(2)).toHaveClass('active');
379379
}));
380380
});
381+
382+
describe('disabled', function() {
383+
beforeEach(inject(function($compile, $rootScope) {
384+
scope = $rootScope.$new();
385+
386+
function makeTab(disabled) {
387+
return {
388+
active: false,
389+
select: jasmine.createSpy(),
390+
disabled: disabled
391+
};
392+
}
393+
scope.tabs = [
394+
makeTab(false), makeTab(true), makeTab(false), makeTab(true)
395+
];
396+
elm = $compile([
397+
'<tabset>',
398+
' <tab ng-repeat="t in tabs" active="t.active" select="t.select()" disabled="t.disabled">',
399+
' <tab-heading><b>heading</b> {{index}}</tab-heading>',
400+
' content {{$index}}',
401+
' </tab>',
402+
'</tabset>'
403+
].join('\n'))(scope);
404+
scope.$apply();
405+
}));
406+
407+
function titles() {
408+
return elm.find('ul.nav-tabs li');
409+
}
410+
function contents() {
411+
return elm.find('div.tab-content div.tab-pane');
412+
}
413+
414+
function expectTabActive(activeTab) {
415+
var _titles = titles();
416+
angular.forEach(scope.tabs, function(tab, i) {
417+
if (activeTab === tab) {
418+
expect(tab.active).toBe(true);
419+
expect(tab.select.callCount).toBe( (tab.disabled) ? 0 : 1 );
420+
expect(_titles.eq(i)).toHaveClass('active');
421+
expect(contents().eq(i).text().trim()).toBe('content ' + i);
422+
expect(contents().eq(i)).toHaveClass('active');
423+
} else {
424+
expect(tab.active).toBe(false);
425+
expect(_titles.eq(i)).not.toHaveClass('active');
426+
}
427+
});
428+
}
429+
430+
it('should not switch active when clicking on title', function() {
431+
titles().eq(2).find('a').click();
432+
expectTabActive(scope.tabs[2]);
433+
434+
titles().eq(3).find('a').click();
435+
expectTabActive(scope.tabs[2]);
436+
});
437+
438+
it('should not switch active when setting active=true', function() {
439+
scope.$apply('tabs[2].active = true');
440+
expectTabActive(scope.tabs[2]);
441+
442+
scope.$apply('tabs[3].active = true');
443+
expectTabActive(scope.tabs[2]);
444+
});
445+
446+
it('should toggle between states', function() {
447+
expect(titles().eq(3)).toHaveClass('disabled');
448+
scope.$apply('tabs[3].disabled = false');
449+
expect(titles().eq(3)).not.toHaveClass('disabled');
450+
451+
expect(titles().eq(2)).not.toHaveClass('disabled');
452+
scope.$apply('tabs[2].disabled = true');
453+
expect(titles().eq(2)).toHaveClass('disabled');
454+
});
455+
});
456+
381457
});

template/tabs/tab.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
<li ng-class="{active: active}">
1+
<li ng-class="{active: active, disabled: disabled}">
22
<a ng-click="select()" tab-heading-transclude>{{heading}}</a>
33
</li>

0 commit comments

Comments
 (0)