From f183c831d68664eeb5b2e8ac62454ccfb12e9542 Mon Sep 17 00:00:00 2001 From: Vincent Leonardo Date: Fri, 9 Sep 2016 23:56:20 +0800 Subject: [PATCH 1/8] Fix Indeterminate State not Triggered from 'false' state Replaced default checkbox formatter to ignore comparing 'undefined' value. --- src/directives/bsSwitch.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/directives/bsSwitch.js b/src/directives/bsSwitch.js index 7e1f7f8..f58f2a6 100644 --- a/src/directives/bsSwitch.js +++ b/src/directives/bsSwitch.js @@ -150,6 +150,12 @@ angular.module('frapontillo.bootstrap-switch') controller.$setViewValue(controller.$modelValue); } else { controller.$setViewValue(viewValue); + controller.$formatters[0] = function(value) { + if (value === undefined) { + return value; + } + return angular.equals(value, getTrueValue()); + } } } }; From 240b51e921cc2a84a510c717cde65e9363286ebf Mon Sep 17 00:00:00 2001 From: Vincent Leonardo Date: Sat, 10 Sep 2016 00:11:50 +0800 Subject: [PATCH 2/8] Missing semicolon --- src/directives/bsSwitch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/directives/bsSwitch.js b/src/directives/bsSwitch.js index f58f2a6..8c46b7e 100644 --- a/src/directives/bsSwitch.js +++ b/src/directives/bsSwitch.js @@ -155,7 +155,7 @@ angular.module('frapontillo.bootstrap-switch') return value; } return angular.equals(value, getTrueValue()); - } + }; } } }; From 26c553777745f953b689885d65b4b00cb14909a9 Mon Sep 17 00:00:00 2001 From: Vincent Leonardo Date: Sat, 10 Sep 2016 01:35:44 +0800 Subject: [PATCH 3/8] Added ignore checking 'null' for formatter --- src/directives/bsSwitch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/directives/bsSwitch.js b/src/directives/bsSwitch.js index 8c46b7e..93b6e59 100644 --- a/src/directives/bsSwitch.js +++ b/src/directives/bsSwitch.js @@ -151,7 +151,7 @@ angular.module('frapontillo.bootstrap-switch') } else { controller.$setViewValue(viewValue); controller.$formatters[0] = function(value) { - if (value === undefined) { + if (value === undefined || value === null) { return value; } return angular.equals(value, getTrueValue()); From 1d5bc20f53a70a66a3f11946110cc5514f71f487 Mon Sep 17 00:00:00 2001 From: Vincent Leonardo Date: Sat, 10 Sep 2016 01:37:46 +0800 Subject: [PATCH 4/8] Added test cases for toggling between indeterminate value --- test/spec/directives/bsSwitchSpec.js | 136 +++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/test/spec/directives/bsSwitchSpec.js b/test/spec/directives/bsSwitchSpec.js index 41bdcdb..9b7c223 100644 --- a/test/spec/directives/bsSwitchSpec.js +++ b/test/spec/directives/bsSwitchSpec.js @@ -723,4 +723,140 @@ describe('Directive: bsSwitch', function () { } it('should evaluate change expression when model changes', inject(makeTestModelSwitchChange())); it('should evaluate change expression when model changes', inject(makeTestModelSwitchChange(true))); + + // Test the null model from true state + function makeTestToIndeterminateNullFromTrue(input) { + return function () { + var element = compileDirective(undefined, input); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeTruthy(); + scope.model = true; + scope.$apply(); + expect(element.hasClass(CONST.SWITCH_INDETERMINATE_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeTruthy(); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeFalsy(); + scope.model = null; + scope.$apply(); + expect(element.hasClass(CONST.SWITCH_INDETERMINATE_CLASS)).toBeTruthy(); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeTruthy(); + }; + } + it('should change from true to the indeterminate state when the model is null', inject(makeTestToIndeterminateNullFromTrue())); + it('should change from true to the indeterminate state when the model is null (input)', inject(makeTestToIndeterminateNullFromTrue(true))); + + // Test the null model from false state + function makeTestToIndeterminateNullFromFalse(input) { + return function () { + var element = compileDirective(undefined, input); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeTruthy(); + scope.model = false; + scope.$apply(); + expect(element.hasClass(CONST.SWITCH_INDETERMINATE_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeTruthy(); + scope.model = null; + scope.$apply(); + expect(element.hasClass(CONST.SWITCH_INDETERMINATE_CLASS)).toBeTruthy(); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeTruthy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeFalsy(); + }; + } + it('should change from false to the indeterminate state when the model is null', inject(makeTestToIndeterminateNullFromFalse())); + it('should change from false to the indeterminate state when the model is null (input)', inject(makeTestToIndeterminateNullFromFalse(true))); + + // Test the undefined model from true state + function makeTestToIndeterminateUndefinedFromTrue(input) { + return function () { + var element = compileDirective(undefined, input); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeTruthy(); + scope.model = true; + scope.$apply(); + expect(element.hasClass(CONST.SWITCH_INDETERMINATE_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeTruthy(); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeFalsy(); + scope.model = undefined; + scope.$apply(); + expect(element.hasClass(CONST.SWITCH_INDETERMINATE_CLASS)).toBeTruthy(); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeTruthy(); + }; + } + it('should change from true to the indeterminate state when the model is null', inject(makeTestToIndeterminateUndefinedFromTrue())); + it('should change from true to the indeterminate state when the model is null (input)', inject(makeTestToIndeterminateUndefinedFromTrue(true))); + + // Test the undefined model from false state + function makeTestToIndeterminateUndefinedFromFalse(input) { + return function () { + var element = compileDirective(undefined, input); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeTruthy(); + scope.model = false; + scope.$apply(); + expect(element.hasClass(CONST.SWITCH_INDETERMINATE_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeTruthy(); + scope.model = undefined; + scope.$apply(); + expect(element.hasClass(CONST.SWITCH_INDETERMINATE_CLASS)).toBeTruthy(); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeTruthy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeFalsy(); + }; + } + it('should change from false to the indeterminate state when the model is null', inject(makeTestToIndeterminateUndefinedFromFalse())); + it('should change from false to the indeterminate state when the model is null (input)', inject(makeTestToIndeterminateUndefinedFromFalse(true))); + + // Test the changing multiple state + function makeTestMultipleChangeOfStateIndeterminate(input) { + return function () { + var element = compileDirective(undefined, input); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeTruthy(); + scope.model = false; + scope.$apply(); + expect(element.hasClass(CONST.SWITCH_INDETERMINATE_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeTruthy(); + scope.model = undefined; + scope.$apply(); + expect(element.hasClass(CONST.SWITCH_INDETERMINATE_CLASS)).toBeTruthy(); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeTruthy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeFalsy(); + scope.model = true; + scope.$apply(); + expect(element.hasClass(CONST.SWITCH_INDETERMINATE_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeTruthy(); + }; + } + it('should change from false to the indeterminate state when the model is null', inject(makeTestMultipleChangeOfStateIndeterminate())); + it('should change from false to the indeterminate state when the model is null (input)', inject(makeTestMultipleChangeOfStateIndeterminate(true))); + + // Test the changing multiple state other way round + function makeTestMultipleChangeOfStateIndeterminateReverse(input) { + return function () { + var element = compileDirective(undefined, input); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeTruthy(); + scope.model = true; + scope.$apply(); + expect(element.hasClass(CONST.SWITCH_INDETERMINATE_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeTruthy(); + scope.model = undefined; + scope.$apply(); + expect(element.hasClass(CONST.SWITCH_INDETERMINATE_CLASS)).toBeTruthy(); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeTruthy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeFalsy(); + scope.model = false; + scope.$apply(); + expect(element.hasClass(CONST.SWITCH_INDETERMINATE_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeTruthy(); + }; + } + it('should change from false to the indeterminate state when the model is null', inject(makeTestMultipleChangeOfStateIndeterminate())); + it('should change from false to the indeterminate state when the model is null (input)', inject(makeTestMultipleChangeOfStateIndeterminate(true))); }); From 97ef133ed6b43e2726a5def4678637ef86d88d77 Mon Sep 17 00:00:00 2001 From: Vincent Leonardo Date: Sat, 10 Sep 2016 01:46:16 +0800 Subject: [PATCH 5/8] Missed out calling some test cases --- test/spec/directives/bsSwitchSpec.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/spec/directives/bsSwitchSpec.js b/test/spec/directives/bsSwitchSpec.js index 9b7c223..4e08aba 100644 --- a/test/spec/directives/bsSwitchSpec.js +++ b/test/spec/directives/bsSwitchSpec.js @@ -831,8 +831,8 @@ describe('Directive: bsSwitch', function () { expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeTruthy(); }; } - it('should change from false to the indeterminate state when the model is null', inject(makeTestMultipleChangeOfStateIndeterminate())); - it('should change from false to the indeterminate state when the model is null (input)', inject(makeTestMultipleChangeOfStateIndeterminate(true))); + it('should change from false to the indeterminate state and to true', inject(makeTestMultipleChangeOfStateIndeterminate())); + it('should change from false to the indeterminate state and to true (input)', inject(makeTestMultipleChangeOfStateIndeterminate(true))); // Test the changing multiple state other way round function makeTestMultipleChangeOfStateIndeterminateReverse(input) { @@ -848,8 +848,8 @@ describe('Directive: bsSwitch', function () { scope.model = undefined; scope.$apply(); expect(element.hasClass(CONST.SWITCH_INDETERMINATE_CLASS)).toBeTruthy(); - expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeTruthy(); - expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeTruthy(); scope.model = false; scope.$apply(); expect(element.hasClass(CONST.SWITCH_INDETERMINATE_CLASS)).toBeFalsy(); @@ -857,6 +857,6 @@ describe('Directive: bsSwitch', function () { expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeTruthy(); }; } - it('should change from false to the indeterminate state when the model is null', inject(makeTestMultipleChangeOfStateIndeterminate())); - it('should change from false to the indeterminate state when the model is null (input)', inject(makeTestMultipleChangeOfStateIndeterminate(true))); + it('should change from false to the indeterminate state and to false', inject(makeTestMultipleChangeOfStateIndeterminateReverse())); + it('should change from false to the indeterminate state and to false (input)', inject(makeTestMultipleChangeOfStateIndeterminateReverse(true))); }); From 5caadacc49ff5945eae8ce1fefc4cb3d73770eb1 Mon Sep 17 00:00:00 2001 From: Olga Karataeva Date: Fri, 1 Dec 2017 13:11:59 +0700 Subject: [PATCH 6/8] Update model value when switch is disabled --- src/directives/bsSwitch.js | 10 ++++++++++ test/spec/directives/bsSwitchSpec.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/directives/bsSwitch.js b/src/directives/bsSwitch.js index 93b6e59..210e2d0 100644 --- a/src/directives/bsSwitch.js +++ b/src/directives/bsSwitch.js @@ -182,6 +182,12 @@ angular.module('frapontillo.bootstrap-switch') // When the model changes controller.$render = function () { initMaybe(); + + // WORKAROUND for https://github.com/Bttstrp/bootstrap-switch/issues/540 + // to update model value when bootstrapSwitch is disabled we should + // re-enable it and only then update 'state' + element.bootstrapSwitch('disabled', ''); + var newValue = controller.$modelValue; if (newValue !== undefined && newValue !== null) { element.bootstrapSwitch('state', newValue === getTrueValue(), true); @@ -189,6 +195,10 @@ angular.module('frapontillo.bootstrap-switch') element.bootstrapSwitch('indeterminate', true, true); controller.$setViewValue(undefined); } + + // return initial value for "disabled" + setActive(); + switchChange(); }; diff --git a/test/spec/directives/bsSwitchSpec.js b/test/spec/directives/bsSwitchSpec.js index 4e08aba..609f414 100644 --- a/test/spec/directives/bsSwitchSpec.js +++ b/test/spec/directives/bsSwitchSpec.js @@ -391,6 +391,34 @@ describe('Directive: bsSwitch', function () { it('should change the model, then deactivate the switch', inject(makeTestChangeModelThenDeactivate())); it('should change the model, deactivate the switch (input)', inject(makeTestChangeModelThenDeactivate(true))); + // Test a model change when switch is deactivated + function makeTestChangeModelWhenSwitchIsDeactivated() { + return function () { + var element = compileDirective('active'); + scope.model = false; + scope.isActive = false; + scope.$apply(); + $timeout.flush(); + // test the active state, should be false + expect(element.hasClass(CONST.SWITCH_DISABLED_CLASS)).toBeTruthy(); + expect(element.find(CONST.INPUT_SELECTOR).attr('disabled')).toBeTruthy(); + // test the model, should be false + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeTruthy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeFalsy(); + + scope.model = true; + scope.$apply(); + + // test the active state, should be false + expect(element.hasClass(CONST.SWITCH_DISABLED_CLASS)).toBeTruthy(); + expect(element.find(CONST.INPUT_SELECTOR).attr('disabled')).toBeTruthy(); + // test the model, should be true + expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeFalsy(); + expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeTruthy(); + }; + } + it('should deactivate the switch, then change the model', inject(makeTestChangeModelWhenSwitchIsDeactivated())); + // Test the activation function makeTestActivate(input) { return function () { From 6203a96d7ca9d55cc31b3ab19954dbd916458852 Mon Sep 17 00:00:00 2001 From: Olga Karataeva Date: Fri, 1 Dec 2017 17:22:19 +0700 Subject: [PATCH 7/8] Code reformatted --- test/spec/directives/bsSwitchSpec.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/spec/directives/bsSwitchSpec.js b/test/spec/directives/bsSwitchSpec.js index 609f414..a44cf0b 100644 --- a/test/spec/directives/bsSwitchSpec.js +++ b/test/spec/directives/bsSwitchSpec.js @@ -406,13 +406,13 @@ describe('Directive: bsSwitch', function () { expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeTruthy(); expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeFalsy(); - scope.model = true; - scope.$apply(); + scope.model = true; + scope.$apply(); - // test the active state, should be false + // test the active state, should be false expect(element.hasClass(CONST.SWITCH_DISABLED_CLASS)).toBeTruthy(); expect(element.find(CONST.INPUT_SELECTOR).attr('disabled')).toBeTruthy(); - // test the model, should be true + // test the model, should be true expect(element.hasClass(CONST.SWITCH_OFF_CLASS)).toBeFalsy(); expect(element.hasClass(CONST.SWITCH_ON_CLASS)).toBeTruthy(); }; From 9c4570b3a36bc88b81decbe78b180421e88e4a4f Mon Sep 17 00:00:00 2001 From: Olga Karataeva Date: Fri, 1 Dec 2017 17:49:26 +0700 Subject: [PATCH 8/8] Code reformatted 2 --- test/spec/directives/bsSwitchSpec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/spec/directives/bsSwitchSpec.js b/test/spec/directives/bsSwitchSpec.js index a44cf0b..07cd1f0 100644 --- a/test/spec/directives/bsSwitchSpec.js +++ b/test/spec/directives/bsSwitchSpec.js @@ -391,7 +391,7 @@ describe('Directive: bsSwitch', function () { it('should change the model, then deactivate the switch', inject(makeTestChangeModelThenDeactivate())); it('should change the model, deactivate the switch (input)', inject(makeTestChangeModelThenDeactivate(true))); - // Test a model change when switch is deactivated + // Test a model change when switch is deactivated function makeTestChangeModelWhenSwitchIsDeactivated() { return function () { var element = compileDirective('active');