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

Commit

Permalink
feat(buttons): add checkbox and radio buttons
Browse files Browse the repository at this point in the history
Closes #53
  • Loading branch information
pkozlowski-opensource committed Feb 18, 2013
1 parent 8708694 commit 571ccf4
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 0 deletions.
76 changes: 76 additions & 0 deletions src/buttons/buttons.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
angular.module('ui.bootstrap.buttons', [])

.constant('buttonConfig', {
activeClass:'active',
toggleEvent:'click'
})

.directive('btnRadio', ['buttonConfig', function (buttonConfig) {
var activeClass = buttonConfig.activeClass || 'active';
var toggleEvent = buttonConfig.toggleEvent || 'click';

return {

require:'ngModel',
link:function (scope, element, attrs, ngModelCtrl) {

var value = scope.$eval(attrs.btnRadio);

//model -> UI
scope.$watch(function () {
return ngModelCtrl.$modelValue;
}, function (modelValue) {
if (angular.equals(modelValue, value)){
element.addClass(activeClass);
} else {
element.removeClass(activeClass);
}
});

//ui->model
element.bind(toggleEvent, function () {
if (!element.hasClass(activeClass)) {
scope.$apply(function () {
ngModelCtrl.$setViewValue(value);
});
}
});
}
};
}])

.directive('btnCheckbox', ['buttonConfig', function (buttonConfig) {

var activeClass = buttonConfig.activeClass || 'active';
var toggleEvent = buttonConfig.toggleEvent || 'click';

return {
require:'ngModel',
link:function (scope, element, attrs, ngModelCtrl) {

var trueValue = scope.$eval(attrs.btnCheckboxTrue);
var falseValue = scope.$eval(attrs.btnCheckboxFalse);

trueValue = angular.isDefined(trueValue) ? trueValue : true;
falseValue = angular.isDefined(falseValue) ? falseValue : false;

//model -> UI
scope.$watch(function () {
return ngModelCtrl.$modelValue;
}, function (modelValue) {
if (angular.equals(modelValue, trueValue)) {
element.addClass(activeClass);
} else {
element.removeClass(activeClass);
}
});

//ui->model
element.bind(toggleEvent, function () {
scope.$apply(function () {
ngModelCtrl.$setViewValue(element.hasClass(activeClass) ? falseValue : trueValue);
});
});
}
};
}]);
21 changes: 21 additions & 0 deletions src/buttons/docs/demo.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<div ng-controller="ButtonsCtrl">
<h4>Single toggle</h4>
<pre>{{singleModel}}</pre>
<button type="button" class="btn btn-primary" ng-model="singleModel" btn-checkbox btn-checkbox-true="1" btn-checkbox-false="0">
Single Toggle
</button>
<h4>Checkbox</h4>
<pre>{{checkModel}}</pre>
<div class="btn-group" data-toggle="buttons-checkbox">
<button type="button" class="btn btn-primary" ng-model="checkModel.left" btn-checkbox>Left</button>
<button type="button" class="btn btn-primary" ng-model="checkModel.middle" btn-checkbox>Middle</button>
<button type="button" class="btn btn-primary" ng-model="checkModel.right" btn-checkbox>Right</button>
</div>
<h4>Radio</h4>
<pre>{{radioModel}}</pre>
<div class="btn-group" data-toggle="buttons-checkbox">
<button type="button" class="btn btn-primary" ng-model="radioModel" btn-radio="'Left'">Left</button>
<button type="button" class="btn btn-primary" ng-model="radioModel" btn-radio="'Middle'">Middle</button>
<button type="button" class="btn btn-primary" ng-model="radioModel" btn-radio="'Right'">Right</button>
</div>
</div>
12 changes: 12 additions & 0 deletions src/buttons/docs/demo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
var ButtonsCtrl = function ($scope) {

$scope.singleModel = 1;

$scope.radioModel = 'Middle';

$scope.checkModel = {
left: false,
middle: true,
right: false
};
};
2 changes: 2 additions & 0 deletions src/buttons/docs/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
There are 2 directives that can make a group of buttons to behave like a set of checkboxes or radio buttons.

94 changes: 94 additions & 0 deletions src/buttons/test/buttons.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
describe('buttons', function () {

var $scope, $compile;

beforeEach(module('ui.bootstrap.buttons'));
beforeEach(inject(function (_$rootScope_, _$compile_) {
$scope = _$rootScope_;
$compile = _$compile_;
}));

describe('checkbox', function () {

var compileButton = function (markup, scope) {
var el = $compile(markup)(scope);
scope.$digest();
return el;
};

//model -> UI
it('should work correctly with default model values', function () {
$scope.model = false;
var btn = compileButton('<button ng-model="model" btn-checkbox>click</button>', $scope);
expect(btn).not.toHaveClass('active');

$scope.model = true;
$scope.$digest();
expect(btn).toHaveClass('active');
});

it('should bind custom model values', function () {
$scope.model = 1;
var btn = compileButton('<button ng-model="model" btn-checkbox btn-checkbox-true="1" btn-checkbox-false="0">click</button>', $scope);
expect(btn).toHaveClass('active');

$scope.model = 0;
$scope.$digest();
expect(btn).not.toHaveClass('active');
});

//UI-> model
it('should toggle default model values on click', function () {
$scope.model = false;
var btn = compileButton('<button ng-model="model" btn-checkbox>click</button>', $scope);

btn.click();
expect($scope.model).toEqual(true);
btn.click();
expect($scope.model).toEqual(false);
});

it('should toggle custom model values on click', function () {
$scope.model = 0;
var btn = compileButton('<button ng-model="model" btn-checkbox btn-checkbox-true="1" btn-checkbox-false="0">click</button>', $scope);

btn.click();
expect($scope.model).toEqual(1);
btn.click();
expect($scope.model).toEqual(0);
});
});

describe('radio', function () {

var compileButtons = function (markup, scope) {
var el = $compile('<div>'+markup+'</div>')(scope);
scope.$digest();
return el.find('button');
};

//model -> UI
it('should work correctly set active class based on model', function () {
var btns = compileButtons('<button ng-model="model" btn-radio="1">click1</button><button ng-model="model" btn-radio="2">click2</button>', $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 work correctly set active class based on model', function () {
var btns = compileButtons('<button ng-model="model" btn-radio="1">click1</button><button ng-model="model" btn-radio="2">click2</button>', $scope);
expect($scope.model).toBeUndefined();

btns.eq(0).click();
expect($scope.model).toEqual(1);

btns.eq(1).click();
expect($scope.model).toEqual(2);
});
});
});

0 comments on commit 571ccf4

Please sign in to comment.