-
Notifications
You must be signed in to change notification settings - Fork 27.5k
Automatic unwrapping of promises by $parse severely limits its usefulness #4158
Comments
When a parsed function call returns a promise, the evaluated value is the resolved value of the promise rather than the promise object. Closes #3503
would it be sufficient if $parse took an optional argument that would tell it to not unwrap promises? |
Sure, I'm going to look into it. |
Sure, an optional argument would solve the problem, though to me opting in to promise unwrapping would make more sense than opting out. |
@wilsonjackson fair enough. we'll consider it |
I mentioned this in my PR that this issue stemmed from, but please make sure that functions returning promises are processed the same way by $parse as promise objects in scope. I don't mind unwrapping being opt-in, but keep in mind that promise objects have been unwrapped automatically for a long time now. |
@IgorMinar an optional opt-in argument would be a perfect solution. We really need it badly for the angular-ui/bootstrap. @jankuca if I help anyhow I could give you a hand with this issue, I'm really keen on doing anything that would speed up this issue resolution. |
I agree that promise objects should be unwrapped (or not) according to the same rules whether they result from a function call or not. I'd argue that promise unwrapping is an "extra" feature that is not intrinsically related to parsing, so it would make the most sense for it not to happen by default. Also, the time to introduce breaking changes is now. I think this is the perfect time to correct this slight overreach in $parse's implementation. |
I did some work regarding this issue: jankuca/angular.js@dddc774...promise_unwrapping But we need to get #3681 first. |
I'll second that this is a pretty big breaking change and it doesn't allow for knowing when the promise is resolved for actions. And now I'm between a rock and a hard place, as RC1 has broken ngIncludes and RC2 has this broken :S Does anyone know what direction you'll take after all so I can at least work around only one of the issues? |
Also note that this affects the behavior of directive & bindings and any options you add need to be able to be applied there too... |
Agreed @georgiosd . Spent about half a day debugging this. |
How about we move the promise unwrapping into the attributeInterpolationDirective, since that is really the only place where it should be expected to automatically unwrap? If you are working with promises in code then you should have full control. |
@petebacondarwin I'm unfamiliar with the attributeInterpolationDirective, would that work transparently with Another thing that might be worth looking into is having the unwrapping option stored in the promise itself. So if we want the promise to be unwrapped we have to flip an opt-in property before it resolves (or at least before the next $parse). |
Another idea: define an |
@jussik I don't like the idea of the promise itself having to be modified. The concern of whether a promise is unwrapped or not belongs entirely to the code initiating a parse. A scope function that returns a promise should make no assumption about how that promise will be used. |
I like @xrg 's idea - leave it to the programmer. One less bit of magic is probably good. |
Some of the suggestions here, when contrasted with the current behavior, bring up an interesting point. Whereas an That being the case, I don't see how anything but a flag passed to |
An So, we could write: |
Doesn't all this defeat the point of auto-unwrapping, which is that it is Either unwrapping happens without any intervention on the template writer's In any case, $parse should not unwrap promises automatically. On 4 October 2013 08:07, xrg notifications@github.com wrote:
|
++ |
I guess @petebacondarwin is right. +1 on ditching :) |
+1 on ditching |
Yeah, ditching the whole thing certainly makes the process clearer, which I'm definite in favour of. I'm just concerned about all of the 1.0 and 1.1 code that would break if automatic unwrapping was removed. It would likely be a lot more than the amount that broke by adding support for unwrapping functions that return promises. |
This reverts commit 3a65822. The change cased regressions in third party components that require promises from getter functions not to be unwrapped. Since we have deprecated the promise unwrapping support in $parse it doesn't make much sense to fix this issue and deal with regressions in third party code. Closes angular#4158
Yey, awesome! But, @IgorMinar I can't see those commits in master: I guess I'm just blind or something is messed up with the git repo.... |
I think they broke something and got reverted... |
This commit disables promise unwrapping and adds $parseProvider.unwrapPromises() getter/setter api that allows developers to turn the feature back on if needed. Promise unwrapping support will be removed from Angular in the future and this setting only allows for enabling it during transitional period. If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a promise (to reduce the noise, each expression is logged only onces). To disable this logging use `$parseProvider.logPromiseWarnings(false)`. Previously promises found anywhere in the expression during expression evaluation would evaluate to undefined while unresolved and to the fulfillment value if fulfilled. This is a feature that didn't prove to be wildly useful or popular, primarily because of the dichotomy between data access in templates (accessed as raw values) and controller code (accessed as promises). In most code we ended up resolving promises manually in controllers or automatically via routing and unifying the model access in this way. Other downsides of automatic promise unwrapping: - when building components it's often desirable to receive the raw promises - adds complexity and slows down expression evaluation - makes expression code pre-generation unattractive due to the amount of code that needs to be generated - makes IDE auto-completion and tool support hard - adds too much magic BREAKING CHANGE: $parse and templates in general will no longer automatically unwrap promises. This feature has been deprecated and if absolutely needed, it can be reenabled during transitional period via `$parseProvider.unwrapPromises(true)` api. Closes #4158 Closes #4270
This reverts commit 3a65822. The change cased regressions in third party components that require promises from getter functions not to be unwrapped. Since we have deprecated the promise unwrapping support in $parse it doesn't make much sense to fix this issue and deal with regressions in third party code. Closes #4158
they are in master now. there was an issue with IE8, but that's fixed now. |
I still don't see a fix with that or a similar title on master. @IgorMinar, has this really been fixed in a completely different commit? |
This is a great feature!! why to take it down? |
Please consider introducing a custom operator (#, @ or something else) to make promise unwrapping explicit.
|
Both cases can be implemented using a function which unwraps the promise (i.e.
|
That's true, but I liked the conciseness of the deprecated functionality. Would be nice to have both conciseness and explicitness. |
Just inject the above function to your $rootScope using a name of your choice, et voila! |
I understand this, but promises are an important concept across the framework, and so having a special support for them in expressions seems logical and consistent. At least for me. Also this support would make it somewhat easier for people new to Angular to start using promises. |
It may seem to be helpful to beginners but in reality it will cause
|
+1 to to a special operator or providing an unwrap function by default. This just saves typing in simple cases (and a lot of cases are simple). What exactly do I gain from $scope.numbers = undefined; as opposed to $scope.numbers = service.getNumbers() ??? I don't mind making the unpacking explicit in the templates. |
This commit disables promise unwrapping and adds $parseProvider.unwrapPromises() getter/setter api that allows developers to turn the feature back on if needed. Promise unwrapping support will be removed from Angular in the future and this setting only allows for enabling it during transitional period. If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a promise (to reduce the noise, each expression is logged only onces). To disable this logging use `$parseProvider.logPromiseWarnings(false)`. Previously promises found anywhere in the expression during expression evaluation would evaluate to undefined while unresolved and to the fulfillment value if fulfilled. This is a feature that didn't prove to be wildly useful or popular, primarily because of the dichotomy between data access in templates (accessed as raw values) and controller code (accessed as promises). In most code we ended up resolving promises manually in controllers or automatically via routing and unifying the model access in this way. Other downsides of automatic promise unwrapping: - when building components it's often desirable to receive the raw promises - adds complexity and slows down expression evaluation - makes expression code pre-generation unattractive due to the amount of code that needs to be generated - makes IDE auto-completion and tool support hard - adds too much magic BREAKING CHANGE: $parse and templates in general will no longer automatically unwrap promises. This feature has been deprecated and if absolutely needed, it can be reenabled during transitional period via `$parseProvider.unwrapPromises(true)` api. Closes angular#4158 Closes angular#4270
This reverts commit 3a65822. The change cased regressions in third party components that require promises from getter functions not to be unwrapped. Since we have deprecated the promise unwrapping support in $parse it doesn't make much sense to fix this issue and deal with regressions in third party code. Closes angular#4158
This commit disables promise unwrapping and adds $parseProvider.unwrapPromises() getter/setter api that allows developers to turn the feature back on if needed. Promise unwrapping support will be removed from Angular in the future and this setting only allows for enabling it during transitional period. If the unwrapping is enabled, Angular will log a warning about each expression that unwraps a promise (to reduce the noise, each expression is logged only onces). To disable this logging use `$parseProvider.logPromiseWarnings(false)`. Previously promises found anywhere in the expression during expression evaluation would evaluate to undefined while unresolved and to the fulfillment value if fulfilled. This is a feature that didn't prove to be wildly useful or popular, primarily because of the dichotomy between data access in templates (accessed as raw values) and controller code (accessed as promises). In most code we ended up resolving promises manually in controllers or automatically via routing and unifying the model access in this way. Other downsides of automatic promise unwrapping: - when building components it's often desirable to receive the raw promises - adds complexity and slows down expression evaluation - makes expression code pre-generation unattractive due to the amount of code that needs to be generated - makes IDE auto-completion and tool support hard - adds too much magic BREAKING CHANGE: $parse and templates in general will no longer automatically unwrap promises. This feature has been deprecated and if absolutely needed, it can be reenabled during transitional period via `$parseProvider.unwrapPromises(true)` api. Closes angular#4158 Closes angular#4270
This reverts commit 3a65822. The change cased regressions in third party components that require promises from getter functions not to be unwrapped. Since we have deprecated the promise unwrapping support in $parse it doesn't make much sense to fix this issue and deal with regressions in third party code. Closes angular#4158
The behavior introduced by 3a65822, which automatically unwraps promises returned by functions invoked by
$parse
, prevents any consumer of an expression from handling promise resolution on its own. More pertinent discussion of the problem exists here: #3503Notably this breaks the typeahead directive in UI bootstrap, as per this issue: angular-ui/bootstrap#949
Here's a simple example of why this change is problematic.
http://plnkr.co/edit/ymxbpR?p=preview
The directive in that plunk executes a function on click (in the same way as
ng-click
) and expects a promise to be returned, which it will use to decorate the link with loading text.Because
$parse
unwraps the promise, the directive has no chance to add its own handlers. If you switch the Angular version to 1.2.0rc1, it works as expected. I don't believe this is an uncommon use case, and certainly not one the framework should prevent from being possible. I hope this can be resolved by the next RC.The text was updated successfully, but these errors were encountered: