From 82df4fb1c48520396c4af2400af632fcfeb1f611 Mon Sep 17 00:00:00 2001 From: Duncan Beevers Date: Thu, 6 Feb 2014 12:13:27 -0600 Subject: [PATCH] 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 --- src/buttons/buttons.js | 6 ++-- src/buttons/docs/demo.html | 9 ++++-- src/buttons/docs/readme.md | 3 +- src/buttons/test/buttons.spec.js | 48 ++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/buttons/buttons.js b/src/buttons/buttons.js index 913523ed16..27237be388 100644 --- a/src/buttons/buttons.js +++ b/src/buttons/buttons.js @@ -24,9 +24,11 @@ angular.module('ui.bootstrap.buttons', []) //ui->model element.bind(buttonsCtrl.toggleEvent, function () { - if (!element.hasClass(buttonsCtrl.activeClass)) { + var isActive = element.hasClass(buttonsCtrl.activeClass); + + if (!isActive || angular.isDefined(attrs.uncheckable)) { scope.$apply(function () { - ngModelCtrl.$setViewValue(scope.$eval(attrs.btnRadio)); + ngModelCtrl.$setViewValue(isActive ? null : scope.$eval(attrs.btnRadio)); ngModelCtrl.$render(); }); } diff --git a/src/buttons/docs/demo.html b/src/buttons/docs/demo.html index 9b2c6bb088..3c7bf2bfc1 100644 --- a/src/buttons/docs/demo.html +++ b/src/buttons/docs/demo.html @@ -11,11 +11,16 @@

Checkbox

-

Radio

-
{{radioModel}}
+

Radio & Uncheckable Radio

+
{{radioModel || 'null'}}
+
+ + + +
\ No newline at end of file diff --git a/src/buttons/docs/readme.md b/src/buttons/docs/readme.md index 73ef6003d1..82e736b107 100644 --- a/src/buttons/docs/readme.md +++ b/src/buttons/docs/readme.md @@ -1,2 +1 @@ -There are 2 directives that can make a group of buttons to behave like a set of checkboxes or radio buttons. - +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. diff --git a/src/buttons/test/buttons.spec.js b/src/buttons/test/buttons.spec.js index 5b4db2c42c..4774b8b5c8 100644 --- a/src/buttons/test/buttons.spec.js +++ b/src/buttons/test/buttons.spec.js @@ -136,5 +136,53 @@ describe('buttons', function () { expect(btns.eq(0)).not.toHaveClass('active'); expect(btns.eq(1)).toHaveClass('active'); }); + + describe('uncheckable', function () { + //model -> UI + it('should set active class based on model', function () { + var btns = compileButtons('', $scope); + expect(btns.eq(0)).not.toHaveClass('active'); + expect(btns.eq(1)).not.toHaveClass('active'); + + $scope.model = 2; + $scope.$digest(); + expect(btns.eq(0)).not.toHaveClass('active'); + expect(btns.eq(1)).toHaveClass('active'); + }); + + //UI->model + it('should unset active class based on model', function () { + var btns = compileButtons('', $scope); + expect($scope.model).toBeUndefined(); + + btns.eq(0).click(); + expect($scope.model).toEqual(1); + expect(btns.eq(0)).toHaveClass('active'); + expect(btns.eq(1)).not.toHaveClass('active'); + + btns.eq(0).click(); + expect($scope.model).toEqual(undefined); + expect(btns.eq(1)).not.toHaveClass('active'); + expect(btns.eq(0)).not.toHaveClass('active'); + }); + + it('should watch btn-radio values and update state', function () { + $scope.values = ['value1', 'value2']; + + var btns = compileButtons('', $scope); + expect(btns.eq(0)).not.toHaveClass('active'); + expect(btns.eq(1)).not.toHaveClass('active'); + + $scope.model = 'value2'; + $scope.$digest(); + expect(btns.eq(0)).not.toHaveClass('active'); + expect(btns.eq(1)).toHaveClass('active'); + + $scope.model = undefined; + $scope.$digest(); + expect(btns.eq(0)).not.toHaveClass('active'); + expect(btns.eq(1)).not.toHaveClass('active'); + }); + }); }); }); \ No newline at end of file