Skip to content
This repository has been archived by the owner on Dec 1, 2023. It is now read-only.

Commit

Permalink
feat(bsTabs): allow to bind selected tab by name
Browse files Browse the repository at this point in the history
  • Loading branch information
just-boris authored and mgcrea committed May 20, 2015
1 parent 432e7e2 commit 5e83951
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 10 deletions.
10 changes: 9 additions & 1 deletion src/tab/docs/tab.demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,14 @@ <h4>bs-pane options</h4>
<p>Disable pane</p>
</td>
</tr>
<tr>
<td>name</td>
<td>string</td>
<td>''</td>
<td>
<p>Tab name. If provided, it will be used for `bsActivePane` instead of number</p>
</td>
</tr>
</tbody>
</table>
</div>
Expand Down Expand Up @@ -192,7 +200,7 @@ <h3>Helper attributes</h3>
<td>bsActivePane</td>
<td>number</td>
<td>
<p>Binds to the active tab pane index (zero based).</p>
<p>Info about current selected tab. If it has the name, it will be here, otherwise – active tab pane index (zero based).</p>
<p>You can use it to set the active tab pane from code or to get the currently active tab pane.</p>
</td>
</tr>
Expand Down
34 changes: 27 additions & 7 deletions src/tab/tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,23 @@ angular.module('mgcrea.ngStrap.tab', [])
self.$activePaneChangeListeners = self.$viewChangeListeners = [];

self.$push = function(pane) {
if(angular.isUndefined(self.$panes.$active)) {
$scope.$setActive(pane.name || 0);
}
self.$panes.push(pane);
};

self.$remove = function(pane) {
var index = self.$panes.indexOf(pane);
var activeIndex = self.$panes.$active;
var active = self.$panes.$active;
var activeIndex;
if(angular.isString(active)) {
activeIndex = self.$panes.map(function(pane) {
return pane.name;
}).indexOf(active);
} else {
activeIndex = self.$panes.$active;
}

// remove pane from $panes array
self.$panes.splice(index, 1);
Expand All @@ -52,17 +63,24 @@ angular.module('mgcrea.ngStrap.tab', [])
// so select the previous one
activeIndex--;
}
self.$setActive(activeIndex);
if(activeIndex >= 0 && activeIndex < self.$panes.length) {
self.$setActive(self.$panes[activeIndex].name || activeIndex);
} else {
self.$setActive();
}
};

self.$panes.$active = 0;
self.$setActive = $scope.$setActive = function(value) {
self.$panes.$active = value;
self.$activePaneChangeListeners.forEach(function(fn) {
fn();
});
};

self.$isActive = $scope.$isActive = function($pane, $index) {
return self.$panes.$active === $pane.name || self.$panes.$active === $index;
};

};

this.$get = function() {
Expand Down Expand Up @@ -103,7 +121,7 @@ angular.module('mgcrea.ngStrap.tab', [])
// modelValue -> $formatters -> viewValue
ngModelCtrl.$formatters.push(function(modelValue) {
// console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);
bsTabsCtrl.$setActive(modelValue * 1);
bsTabsCtrl.$setActive(modelValue);
return modelValue;
});

Expand All @@ -121,7 +139,7 @@ angular.module('mgcrea.ngStrap.tab', [])

// watch bsActivePane for value changes
scope.$watch(attrs.bsActivePane, function(newValue, oldValue) {
bsTabsCtrl.$setActive(newValue * 1);
bsTabsCtrl.$setActive(newValue);
}, true);
}
}
Expand All @@ -147,6 +165,9 @@ angular.module('mgcrea.ngStrap.tab', [])
scope.title = $sce.trustAsHtml(newValue);
});

// Save tab name into scope
scope.name = attrs.name;

// Add animation class
if(bsTabsCtrl.$options.animation) {
element.addClass(bsTabsCtrl.$options.animation);
Expand All @@ -166,8 +187,7 @@ angular.module('mgcrea.ngStrap.tab', [])

function render() {
var index = bsTabsCtrl.$panes.indexOf(scope);
var active = bsTabsCtrl.$panes.$active;
$animate[index === active ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass);
$animate[bsTabsCtrl.$isActive(scope, index) ? 'addClass' : 'removeClass'](element, bsTabsCtrl.$options.activeClass);
}

bsTabsCtrl.$activePaneChangeListeners.push(function() {
Expand Down
4 changes: 2 additions & 2 deletions src/tab/tab.tpl.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<ul class="nav" ng-class="$navClass" role="tablist">
<li role="presentation" ng-repeat="$pane in $panes track by $index" ng-class="[ $index == $panes.$active ? $activeClass : '', $pane.disabled ? 'disabled' : '' ]">
<a role="tab" data-toggle="tab" ng-click="!$pane.disabled && $setActive($index)" data-index="{{ $index }}" ng-bind-html="$pane.title" aria-controls="$pane.title"></a>
<li role="presentation" ng-repeat="$pane in $panes track by $index" ng-class="[ $isActive($pane, $index) ? $activeClass : '', $pane.disabled ? 'disabled' : '' ]">
<a role="tab" data-toggle="tab" ng-click="!$pane.disabled && $setActive($pane.name || $index)" data-index="{{ $index }}" ng-bind-html="$pane.title" aria-controls="$pane.title"></a>
</li>
</ul>
<div ng-transclude class="tab-content">
Expand Down
20 changes: 20 additions & 0 deletions src/tab/test/tab.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ describe('tab', function () {
scope: {tab: {active: 1}},
element: '<div ng-model="tab.active" bs-tabs><div title="title-1" bs-pane>content-1</div><div title="title-2" bs-pane>content-2</div></div>'
},
'binding-named-ngModel': {
scope: {tab: {active: 'title-1'}},
element: '<div ng-model="tab.active" bs-tabs><div title="title-1" name="title-1" bs-pane>content-1</div><div title="title-2" name="title-2" bs-pane>content-2</div></div>'
},
'template-ngModel-ngRepeat': {
scope: {
tab: {active: 1},
Expand All @@ -50,6 +54,10 @@ describe('tab', function () {
]},
element: '<div ng-model="tab.active" bs-tabs><div ng-repeat="tab in tabs" title="{{ tab.title }}" ng-bind="tab.content" bs-pane></div>'
},
'binding-named-bsActivePane': {
scope: {tab: {active: 'title-1'}},
element: '<div bs-active-pane="tab.active" bs-tabs><div title="title-1" name="title-1" bs-pane>content-1</div><div title="title-2" name="title-2" bs-pane>content-2</div></div>'
},
'binding-bsActivePane': {
scope: {tab: {active: 1}},
element: '<div bs-active-pane="tab.active" bs-tabs><div title="title-1" bs-pane>content-1</div><div title="title-2" bs-pane>content-2</div></div>'
Expand Down Expand Up @@ -212,6 +220,18 @@ describe('tab', function () {
expect(scope.tab.active).toBe(0);
});

it('should set active tab by name', function() {
var elm = compileDirective('binding-named-' + bindingAttribute, {tab: {active: 'title-2'}});
expect(sandboxEl.find('.nav-tabs > li.active').index()).toBe(1);
expect(sandboxEl.find('.tab-content > .tab-pane.active').attr('name')).toBe('title-2');
});

it('should set tab name into model if it is provided', function() {
var elm = compileDirective('binding-named-' + bindingAttribute);
sandboxEl.find('.nav-tabs > li:eq(1) > a').triggerHandler('click');
expect(scope.tab.active).toBe('title-2');
});

it('should keep active pane when adding a new pane after', function() {
var elm = compileDirective('template-' + bindingAttribute + '-ngRepeat');
expect(sandboxEl.find('.nav-tabs > li.active').index()).toBe(1);
Expand Down

0 comments on commit 5e83951

Please sign in to comment.