-
Notifications
You must be signed in to change notification settings - Fork 27.5k
fix(core): drop the toBoolean function #7960
Conversation
Thanks for the PR! Please check the items below to help us merge this faster. See the contributing docs for more information.
If you need to make changes to your pull request, you can update the commit with Thanks again for your help! |
This issue has been a focus of problems for some users and we discussed it on the IRC that it should be at least documented. ~Amended the style to use bootstrap notes, I think overall it looks better and catches the eyes more easily. However there are no anchor links to these, if these are necessary they can be added later. Closes #3436 Closes #5762
@@ -87,7 +87,7 @@ var ngIfDirective = ['$animate', function($animate) { | |||
var block, childScope, previousElements; | |||
$scope.$watch($attr.ngIf, function ngIfWatchAction(value) { | |||
|
|||
if (toBoolean(value)) { | |||
if (!!value) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the !!
is unnecessary here, truthy is truthy regardless
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, sorry for that.
I think you probably want some tests for the other areas affected by the change, such as ngIf and ngAnimate, but that's just me |
I'm also not sure this really adds anything amazing over the closed PRs |
This change looks good to me except for the unnecessary casts to boolean. Please add a test that verifies that |
@@ -917,7 +917,7 @@ function textInputType(scope, element, attr, ctrl, $sniffer, $browser) { | |||
// By default we will trim the value | |||
// If the attribute ng-trim exists we will avoid trimming | |||
// e.g. <input ng-model="foo" ng-trim="false"> | |||
if (toBoolean(attr.ngTrim || 'T')) { | |||
if (!attr.ngTrim || attr.ngTrim !== 'false') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just if (attr.ngTrim !== 'false') {
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This catches the case where attr.ngTrim === false
as well as attr.ngTrim === 'false'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's not clear that we really want to test for it to equal 'false' if the point of this PR is to get rid of toBoolean-like behaviour, though. Why not just !attr.ngTrim
? I guess we aren't parsing it, hmm.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, sorry for the noise
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, it catches both when attr.ngTrim === undefined
(not false
) and when attr.ngTrim === 'false'
. attr.ngTrim
is either undefined or a string, like all attr
values.
So yeah, we're not parsing it (I don't know why), so we have to sort-of parse it here.
Btw, that also means ng-trim="some_falsy_variable"
won't work, why is it implemented in this way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cost of watching, probably
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we just assumed that this is a "static" setting so we didn't want to complicate the implementation with parsing and full expression support.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should consider moving this to ngModelOptions now that we have it. but that's for a separate PR.
@petebacondarwin what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree @IgorMinar - it is a good candidate for ngModelOptions. @shahata - perhaps another one of your nice PRs?
Nothing amazing here. ;) But as for PRs, #7776 just adds docs about this weird behavior to Maybe I'll incorporate tests from @lgalfaso to a separate commit after merging this one (I'd still modify them a bit; now that I looked at it, |
@lgalfaso Thanks. I added wrapping in |
@IgorMinar @caitp @lgalfaso PR updated. I added more tests and changed some other needed things so please review again. |
@@ -85,9 +85,9 @@ var ngIfDirective = ['$animate', function($animate) { | |||
$$tlb: true, | |||
link: function ($scope, $element, $attr, ctrl, $transclude) { | |||
var block, childScope, previousElements; | |||
$scope.$watch($attr.ngIf, function ngIfWatchAction(value) { | |||
$scope.$watch('!!(' + $attr.ngIf + ')', function ngIfWatchAction(value) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this doesn't look right to me. we should be able to handle even []
or {}
without infinite loop.
ahh... I see. when we added one-time binding, we broke this because the constants are not unwatched after the digest loop which is too late and that causes infinite digest. cc: @lgalfaso @rodyhaddad
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, this does not look right. Let me look into this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, so I guess I'll wait for #7970 and then remove this wrapping? This does cause the watcher to fire when changing from a truthy value to another truthy value; is there any performance difference between evaluating:
$scope.$watch('foo', handler);
and
$scope.$watch('!!foo', handler);
?
"Adding" an existing class should be a noop, so the cost is mainly due to invoking the watch handler; if changing a simple field to an expression adds new functions to the pipeline, there should be no perf difference.
I asked pete to merge #7970 today so this one is unblocked. |
So I should revert the |
So far Angular have used the toBoolean function to decide if the parsed value is truthy. The function made more values falsy than regular JavaScript would, e.g. strings 'f' and 'no' were both treated as falsy. This creates suble bugs when backend sends a non-empty string with one of these values and something suddenly hides in the application Thanks to lgalfaso for test ideas. BREAKING CHANGE: values 'f', '0', 'false', 'no', 'n', '[]' are no longer treated as falsy. Only JavaScript falsy values are now treated as falsy by the expression parser; there are six of them: false, null, undefined, NaN, 0 and "". Fixes angular#3969 Fixes angular#4277
@IgorMinar I rebased (#7970 was merged) and removed |
looks great to me |
Awesome. Thanks!
|
So far Angular have used the toBoolean function to decide if the parsed value is truthy. The function made more values falsy than regular JavaScript would, e.g. strings 'f' and 'no' were both treated as falsy. This creates suble bugs when backend sends a non-empty string with one of these values and something suddenly hides in the application Thanks to lgalfaso for test ideas. BREAKING CHANGE: values 'f', '0', 'false', 'no', 'n', '[]' are no longer treated as falsy. Only JavaScript falsy values are now treated as falsy by the expression parser; there are six of them: false, null, undefined, NaN, 0 and "". Closes angular#3969 Closes angular#4277 Closes angular#7960
So far Angular have used the toBoolean function to decide if the parsed value
is truthy. The function made more values falsy than regular JavaScript would,
e.g. strings 'f' and 'no' were both treated as falsy. This creates suble bugs
when backend sends a non-empty string with one of these values and something
suddenly hides in the application
BREAKING CHANGE: values 'f', '0', 'false', 'no', 'n', '[]' are no longer
treated as falsy. Only JavaScript falsy values are now treated as falsy by the
expression parser; there are six of them: false, null, undefined, NaN, 0 and "".
Fixes #3969
Fixes #4277
cc @IgorMinar @petebacondarwin