diff --git a/src/buttons/buttons.js b/src/buttons/buttons.js new file mode 100644 index 0000000000..426b2996cd --- /dev/null +++ b/src/buttons/buttons.js @@ -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); + }); + }); + } + }; +}]); \ No newline at end of file diff --git a/src/buttons/docs/demo.html b/src/buttons/docs/demo.html new file mode 100644 index 0000000000..b810b685b4 --- /dev/null +++ b/src/buttons/docs/demo.html @@ -0,0 +1,21 @@ +
+

Single toggle

+
{{singleModel}}
+ +

Checkbox

+
{{checkModel}}
+
+ + + +
+

Radio

+
{{radioModel}}
+
+ + + +
+
\ No newline at end of file diff --git a/src/buttons/docs/demo.js b/src/buttons/docs/demo.js new file mode 100644 index 0000000000..71bc1880ee --- /dev/null +++ b/src/buttons/docs/demo.js @@ -0,0 +1,12 @@ +var ButtonsCtrl = function ($scope) { + + $scope.singleModel = 1; + + $scope.radioModel = 'Middle'; + + $scope.checkModel = { + left: false, + middle: true, + right: false + }; +}; \ No newline at end of file diff --git a/src/buttons/docs/readme.md b/src/buttons/docs/readme.md new file mode 100644 index 0000000000..8bf3c23e32 --- /dev/null +++ b/src/buttons/docs/readme.md @@ -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. + diff --git a/src/buttons/test/buttons.spec.js b/src/buttons/test/buttons.spec.js new file mode 100644 index 0000000000..21748457f9 --- /dev/null +++ b/src/buttons/test/buttons.spec.js @@ -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('', $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('', $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('', $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('', $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('
'+markup+'
')(scope); + scope.$digest(); + return el.find('button'); + }; + + //model -> UI + it('should work correctly 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 work correctly set active class based on model', function () { + var btns = compileButtons('', $scope); + expect($scope.model).toBeUndefined(); + + btns.eq(0).click(); + expect($scope.model).toEqual(1); + + btns.eq(1).click(); + expect($scope.model).toEqual(2); + }); + }); +}); \ No newline at end of file