From 450d5b322e47d60c77856b2d0c2d19171f428e6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20Galfas=C3=B3?= Date: Wed, 5 Feb 2014 22:50:15 +0100 Subject: [PATCH] fix(ingIf/ngShow/ngHide): follow javscript `truthy`/`falsy` logic Make ngShow and ngHide follow javascript `truthy`/`falsy` logic and not the custom toBoolean logic Fixes #5414 #4277 #3969 BREAKING CHANGE: The expressions * `
X
` * `
X
` * `
X
` used to be evaluated to `false` and the elements were hidden. The same effect is present for `ng-show` and the elements are now visible; and with `ng-if` and the elements are now removed If you were previously doing `ng-show="exp"` where `$scope.exp = 'no' // (or 'n' or 'f')`, then instead write `ng-show="exp && exp !== 'no'` (or 'n' or 'f'). --- src/ng/directive/ngIf.js | 4 ++-- src/ng/directive/ngShowHide.js | 8 ++++---- test/BinderSpec.js | 4 ++-- test/ng/directive/ngIfSpec.js | 12 ++++++++++++ test/ng/directive/ngShowHideSpec.js | 24 ++++++++++++++++++++++++ 5 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/ng/directive/ngIf.js b/src/ng/directive/ngIf.js index e132f13b02eb..268e2bbecc66 100644 --- a/src/ng/directive/ngIf.js +++ b/src/ng/directive/ngIf.js @@ -85,9 +85,9 @@ var ngIfDirective = ['$animate', function($animate) { $$tlb: true, link: function ($scope, $element, $attr, ctrl, $transclude) { var block, childScope; - $scope.$watch($attr.ngIf, function ngIfWatchAction(value) { + $scope.$watch('!!(' + $attr.ngIf + ')', function ngIfWatchAction(value) { - if (toBoolean(value)) { + if (value) { if (!childScope) { childScope = $scope.$new(); $transclude(childScope, function (clone) { diff --git a/src/ng/directive/ngShowHide.js b/src/ng/directive/ngShowHide.js index ba33bb1a69de..eab90b70a6c9 100644 --- a/src/ng/directive/ngShowHide.js +++ b/src/ng/directive/ngShowHide.js @@ -150,8 +150,8 @@ */ var ngShowDirective = ['$animate', function($animate) { return function(scope, element, attr) { - scope.$watch(attr.ngShow, function ngShowWatchAction(value){ - $animate[toBoolean(value) ? 'removeClass' : 'addClass'](element, 'ng-hide'); + scope.$watch('!!(' + attr.ngShow + ')', function ngShowWatchAction(value){ + $animate[value ? 'removeClass' : 'addClass'](element, 'ng-hide'); }); }; }]; @@ -307,8 +307,8 @@ var ngShowDirective = ['$animate', function($animate) { */ var ngHideDirective = ['$animate', function($animate) { return function(scope, element, attr) { - scope.$watch(attr.ngHide, function ngHideWatchAction(value){ - $animate[toBoolean(value) ? 'addClass' : 'removeClass'](element, 'ng-hide'); + scope.$watch('!!(' + attr.ngHide + ')', function ngHideWatchAction(value){ + $animate[value ? 'addClass' : 'removeClass'](element, 'ng-hide'); }); }; }]; diff --git a/test/BinderSpec.js b/test/BinderSpec.js index b553c68dcfd0..8f1a9da1abc4 100644 --- a/test/BinderSpec.js +++ b/test/BinderSpec.js @@ -272,7 +272,7 @@ describe('Binder', function() { $rootScope.hidden = 'false'; $rootScope.$apply(); - assertVisible(element); + assertHidden(element); $rootScope.hidden = ''; $rootScope.$apply(); @@ -291,7 +291,7 @@ describe('Binder', function() { $rootScope.show = 'false'; $rootScope.$apply(); - assertHidden(element); + assertVisible(element); $rootScope.show = ''; $rootScope.$apply(); diff --git a/test/ng/directive/ngIfSpec.js b/test/ng/directive/ngIfSpec.js index db923150502b..73f90a93e225 100755 --- a/test/ng/directive/ngIfSpec.js +++ b/test/ng/directive/ngIfSpec.js @@ -136,6 +136,18 @@ describe('ngIf', function () { expect(element.text()).toBe('before;after;'); }); + it('should evaluate using javascript `truthy`/`falsy` logic', function () { + var cases = ['[]', 'f', [], [''], 'false', {}, function() {}, function(f) {}, 0, false, null, undefined, '', NaN]; + element.append($compile( + '
Lucas
' + )($scope)); + angular.forEach(cases, function(value) { + $scope.value = value; + $scope.$apply(); + expect(element.text()).toBe(value ? 'Lucas' : ''); + }); + }); + it('should restore the element to its compiled state', function() { $scope.value = true; makeIf('value'); diff --git a/test/ng/directive/ngShowHideSpec.js b/test/ng/directive/ngShowHideSpec.js index 30397c4cf0fb..ac4ab5a27c80 100644 --- a/test/ng/directive/ngShowHideSpec.js +++ b/test/ng/directive/ngShowHideSpec.js @@ -38,6 +38,18 @@ describe('ngShow / ngHide', function() { $rootScope.$digest(); expect(element).toBeShown(); })); + + + it('should follow javascript `truthy`/`falsy` logic', inject(function($rootScope, $compile) { + var cases = ['[]', 'f', [], [''], 'false', {}, function() {}, function(f) {}, 0, false, null, undefined, '', NaN]; + element = jqLite('
'); + element = $compile(element)($rootScope); + angular.forEach(cases, function(value) { + $rootScope.exp = value; + $rootScope.$digest(); + expect(element)[value ? 'toBeShown' : 'toBeHidden'](); + }); + })); }); describe('ngHide', function() { @@ -49,6 +61,18 @@ describe('ngShow / ngHide', function() { $rootScope.$digest(); expect(element).toBeHidden(); })); + + + it('should follow javascript `truthy`/`falsy` logic', inject(function($rootScope, $compile) { + var cases = ['[]', 'f', [], [''], 'false', {}, function() {}, function(f) {}, 0, false, null, undefined, '', NaN]; + element = jqLite('
'); + element = $compile(element)($rootScope); + angular.forEach(cases, function(value) { + $rootScope.exp = value; + $rootScope.$digest(); + expect(element)[value ? 'toBeHidden' : 'toBeShown'](); + }); + })); }); });