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

Commit 571ccf4

Browse files
feat(buttons): add checkbox and radio buttons
Closes #53
1 parent 8708694 commit 571ccf4

File tree

5 files changed

+205
-0
lines changed

5 files changed

+205
-0
lines changed

src/buttons/buttons.js

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
angular.module('ui.bootstrap.buttons', [])
2+
3+
.constant('buttonConfig', {
4+
activeClass:'active',
5+
toggleEvent:'click'
6+
})
7+
8+
.directive('btnRadio', ['buttonConfig', function (buttonConfig) {
9+
var activeClass = buttonConfig.activeClass || 'active';
10+
var toggleEvent = buttonConfig.toggleEvent || 'click';
11+
12+
return {
13+
14+
require:'ngModel',
15+
link:function (scope, element, attrs, ngModelCtrl) {
16+
17+
var value = scope.$eval(attrs.btnRadio);
18+
19+
//model -> UI
20+
scope.$watch(function () {
21+
return ngModelCtrl.$modelValue;
22+
}, function (modelValue) {
23+
if (angular.equals(modelValue, value)){
24+
element.addClass(activeClass);
25+
} else {
26+
element.removeClass(activeClass);
27+
}
28+
});
29+
30+
//ui->model
31+
element.bind(toggleEvent, function () {
32+
if (!element.hasClass(activeClass)) {
33+
scope.$apply(function () {
34+
ngModelCtrl.$setViewValue(value);
35+
});
36+
}
37+
});
38+
}
39+
};
40+
}])
41+
42+
.directive('btnCheckbox', ['buttonConfig', function (buttonConfig) {
43+
44+
var activeClass = buttonConfig.activeClass || 'active';
45+
var toggleEvent = buttonConfig.toggleEvent || 'click';
46+
47+
return {
48+
require:'ngModel',
49+
link:function (scope, element, attrs, ngModelCtrl) {
50+
51+
var trueValue = scope.$eval(attrs.btnCheckboxTrue);
52+
var falseValue = scope.$eval(attrs.btnCheckboxFalse);
53+
54+
trueValue = angular.isDefined(trueValue) ? trueValue : true;
55+
falseValue = angular.isDefined(falseValue) ? falseValue : false;
56+
57+
//model -> UI
58+
scope.$watch(function () {
59+
return ngModelCtrl.$modelValue;
60+
}, function (modelValue) {
61+
if (angular.equals(modelValue, trueValue)) {
62+
element.addClass(activeClass);
63+
} else {
64+
element.removeClass(activeClass);
65+
}
66+
});
67+
68+
//ui->model
69+
element.bind(toggleEvent, function () {
70+
scope.$apply(function () {
71+
ngModelCtrl.$setViewValue(element.hasClass(activeClass) ? falseValue : trueValue);
72+
});
73+
});
74+
}
75+
};
76+
}]);

src/buttons/docs/demo.html

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<div ng-controller="ButtonsCtrl">
2+
<h4>Single toggle</h4>
3+
<pre>{{singleModel}}</pre>
4+
<button type="button" class="btn btn-primary" ng-model="singleModel" btn-checkbox btn-checkbox-true="1" btn-checkbox-false="0">
5+
Single Toggle
6+
</button>
7+
<h4>Checkbox</h4>
8+
<pre>{{checkModel}}</pre>
9+
<div class="btn-group" data-toggle="buttons-checkbox">
10+
<button type="button" class="btn btn-primary" ng-model="checkModel.left" btn-checkbox>Left</button>
11+
<button type="button" class="btn btn-primary" ng-model="checkModel.middle" btn-checkbox>Middle</button>
12+
<button type="button" class="btn btn-primary" ng-model="checkModel.right" btn-checkbox>Right</button>
13+
</div>
14+
<h4>Radio</h4>
15+
<pre>{{radioModel}}</pre>
16+
<div class="btn-group" data-toggle="buttons-checkbox">
17+
<button type="button" class="btn btn-primary" ng-model="radioModel" btn-radio="'Left'">Left</button>
18+
<button type="button" class="btn btn-primary" ng-model="radioModel" btn-radio="'Middle'">Middle</button>
19+
<button type="button" class="btn btn-primary" ng-model="radioModel" btn-radio="'Right'">Right</button>
20+
</div>
21+
</div>

src/buttons/docs/demo.js

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
var ButtonsCtrl = function ($scope) {
2+
3+
$scope.singleModel = 1;
4+
5+
$scope.radioModel = 'Middle';
6+
7+
$scope.checkModel = {
8+
left: false,
9+
middle: true,
10+
right: false
11+
};
12+
};

src/buttons/docs/readme.md

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

src/buttons/test/buttons.spec.js

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
describe('buttons', function () {
2+
3+
var $scope, $compile;
4+
5+
beforeEach(module('ui.bootstrap.buttons'));
6+
beforeEach(inject(function (_$rootScope_, _$compile_) {
7+
$scope = _$rootScope_;
8+
$compile = _$compile_;
9+
}));
10+
11+
describe('checkbox', function () {
12+
13+
var compileButton = function (markup, scope) {
14+
var el = $compile(markup)(scope);
15+
scope.$digest();
16+
return el;
17+
};
18+
19+
//model -> UI
20+
it('should work correctly with default model values', function () {
21+
$scope.model = false;
22+
var btn = compileButton('<button ng-model="model" btn-checkbox>click</button>', $scope);
23+
expect(btn).not.toHaveClass('active');
24+
25+
$scope.model = true;
26+
$scope.$digest();
27+
expect(btn).toHaveClass('active');
28+
});
29+
30+
it('should bind custom model values', function () {
31+
$scope.model = 1;
32+
var btn = compileButton('<button ng-model="model" btn-checkbox btn-checkbox-true="1" btn-checkbox-false="0">click</button>', $scope);
33+
expect(btn).toHaveClass('active');
34+
35+
$scope.model = 0;
36+
$scope.$digest();
37+
expect(btn).not.toHaveClass('active');
38+
});
39+
40+
//UI-> model
41+
it('should toggle default model values on click', function () {
42+
$scope.model = false;
43+
var btn = compileButton('<button ng-model="model" btn-checkbox>click</button>', $scope);
44+
45+
btn.click();
46+
expect($scope.model).toEqual(true);
47+
btn.click();
48+
expect($scope.model).toEqual(false);
49+
});
50+
51+
it('should toggle custom model values on click', function () {
52+
$scope.model = 0;
53+
var btn = compileButton('<button ng-model="model" btn-checkbox btn-checkbox-true="1" btn-checkbox-false="0">click</button>', $scope);
54+
55+
btn.click();
56+
expect($scope.model).toEqual(1);
57+
btn.click();
58+
expect($scope.model).toEqual(0);
59+
});
60+
});
61+
62+
describe('radio', function () {
63+
64+
var compileButtons = function (markup, scope) {
65+
var el = $compile('<div>'+markup+'</div>')(scope);
66+
scope.$digest();
67+
return el.find('button');
68+
};
69+
70+
//model -> UI
71+
it('should work correctly set active class based on model', function () {
72+
var btns = compileButtons('<button ng-model="model" btn-radio="1">click1</button><button ng-model="model" btn-radio="2">click2</button>', $scope);
73+
expect(btns.eq(0)).not.toHaveClass('active');
74+
expect(btns.eq(1)).not.toHaveClass('active');
75+
76+
$scope.model = 2;
77+
$scope.$digest();
78+
expect(btns.eq(0)).not.toHaveClass('active');
79+
expect(btns.eq(1)).toHaveClass('active');
80+
});
81+
82+
//UI->model
83+
it('should work correctly set active class based on model', function () {
84+
var btns = compileButtons('<button ng-model="model" btn-radio="1">click1</button><button ng-model="model" btn-radio="2">click2</button>', $scope);
85+
expect($scope.model).toBeUndefined();
86+
87+
btns.eq(0).click();
88+
expect($scope.model).toEqual(1);
89+
90+
btns.eq(1).click();
91+
expect($scope.model).toEqual(2);
92+
});
93+
});
94+
});

0 commit comments

Comments
 (0)