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

Commit 82df4fb

Browse files
duncanbeeversbekos
authored andcommitted
feat(button): allow uncheckable radio button
Acts as a hybrid checkbox/radio-button, selecting exclusively among the button set, but also allowing the selected item to be unselected, leaving the button set without a selected item. Closes #1760
1 parent f48e433 commit 82df4fb

File tree

4 files changed

+60
-6
lines changed

4 files changed

+60
-6
lines changed

src/buttons/buttons.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ angular.module('ui.bootstrap.buttons', [])
2424

2525
//ui->model
2626
element.bind(buttonsCtrl.toggleEvent, function () {
27-
if (!element.hasClass(buttonsCtrl.activeClass)) {
27+
var isActive = element.hasClass(buttonsCtrl.activeClass);
28+
29+
if (!isActive || angular.isDefined(attrs.uncheckable)) {
2830
scope.$apply(function () {
29-
ngModelCtrl.$setViewValue(scope.$eval(attrs.btnRadio));
31+
ngModelCtrl.$setViewValue(isActive ? null : scope.$eval(attrs.btnRadio));
3032
ngModelCtrl.$render();
3133
});
3234
}

src/buttons/docs/demo.html

+7-2
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@ <h4>Checkbox</h4>
1111
<label class="btn btn-primary" ng-model="checkModel.middle" btn-checkbox>Middle</label>
1212
<label class="btn btn-primary" ng-model="checkModel.right" btn-checkbox>Right</label>
1313
</div>
14-
<h4>Radio</h4>
15-
<pre>{{radioModel}}</pre>
14+
<h4>Radio &amp; Uncheckable Radio</h4>
15+
<pre>{{radioModel || 'null'}}</pre>
1616
<div class="btn-group">
1717
<label class="btn btn-primary" ng-model="radioModel" btn-radio="'Left'">Left</label>
1818
<label class="btn btn-primary" ng-model="radioModel" btn-radio="'Middle'">Middle</label>
1919
<label class="btn btn-primary" ng-model="radioModel" btn-radio="'Right'">Right</label>
2020
</div>
21+
<div class="btn-group">
22+
<label class="btn btn-success" ng-model="radioModel" btn-radio="'Left'" uncheckable>Left</label>
23+
<label class="btn btn-success" ng-model="radioModel" btn-radio="'Middle'" uncheckable>Middle</label>
24+
<label class="btn btn-success" ng-model="radioModel" btn-radio="'Right'" uncheckable>Right</label>
25+
</div>
2126
</div>

src/buttons/docs/readme.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
There are 2 directives that can make a group of buttons to behave like a set of checkboxes or radio buttons.
2-
1+
There are two directives that can make a group of buttons behave like a set of checkboxes, radio buttons, or a hybrid where radio buttons can be unchecked.

src/buttons/test/buttons.spec.js

+48
Original file line numberDiff line numberDiff line change
@@ -136,5 +136,53 @@ describe('buttons', function () {
136136
expect(btns.eq(0)).not.toHaveClass('active');
137137
expect(btns.eq(1)).toHaveClass('active');
138138
});
139+
140+
describe('uncheckable', function () {
141+
//model -> UI
142+
it('should set active class based on model', function () {
143+
var btns = compileButtons('<button ng-model="model" btn-radio="1" uncheckable>click1</button><button ng-model="model" btn-radio="2" uncheckable>click2</button>', $scope);
144+
expect(btns.eq(0)).not.toHaveClass('active');
145+
expect(btns.eq(1)).not.toHaveClass('active');
146+
147+
$scope.model = 2;
148+
$scope.$digest();
149+
expect(btns.eq(0)).not.toHaveClass('active');
150+
expect(btns.eq(1)).toHaveClass('active');
151+
});
152+
153+
//UI->model
154+
it('should unset active class based on model', function () {
155+
var btns = compileButtons('<button ng-model="model" btn-radio="1" uncheckable>click1</button><button ng-model="model" btn-radio="2" uncheckable>click2</button>', $scope);
156+
expect($scope.model).toBeUndefined();
157+
158+
btns.eq(0).click();
159+
expect($scope.model).toEqual(1);
160+
expect(btns.eq(0)).toHaveClass('active');
161+
expect(btns.eq(1)).not.toHaveClass('active');
162+
163+
btns.eq(0).click();
164+
expect($scope.model).toEqual(undefined);
165+
expect(btns.eq(1)).not.toHaveClass('active');
166+
expect(btns.eq(0)).not.toHaveClass('active');
167+
});
168+
169+
it('should watch btn-radio values and update state', function () {
170+
$scope.values = ['value1', 'value2'];
171+
172+
var btns = compileButtons('<button ng-model="model" btn-radio="values[0]" uncheckable>click1</button><button ng-model="model" btn-radio="values[1]" uncheckable>click2</button>', $scope);
173+
expect(btns.eq(0)).not.toHaveClass('active');
174+
expect(btns.eq(1)).not.toHaveClass('active');
175+
176+
$scope.model = 'value2';
177+
$scope.$digest();
178+
expect(btns.eq(0)).not.toHaveClass('active');
179+
expect(btns.eq(1)).toHaveClass('active');
180+
181+
$scope.model = undefined;
182+
$scope.$digest();
183+
expect(btns.eq(0)).not.toHaveClass('active');
184+
expect(btns.eq(1)).not.toHaveClass('active');
185+
});
186+
});
139187
});
140188
});

0 commit comments

Comments
 (0)