-
Notifications
You must be signed in to change notification settings - Fork 27.5k
Properties set before constructor is called when using bindToController #14206
Comments
The constructor is called in the following lines after the properties have been set in nodeLinkFn. var controllerResult = controller(); The properties setters created using Object.defineProperty are invoked even though the constructor has not yet been invoked. This is problematic if the property setters rely on values initialized in the constructor (in my case throwing exceptions). |
This actually a feature not a bug :) We are binding the properties, so you can work right away from the constructor with them. Maybe you could check if |
With respect, I would suggest breaking the semantics of classes is a BUG and not a feature. As ECMA 6 becomes standard with property getters and setters this type of issue will become more common. It is called a "constructor" after all and controllers in all other areas of angular would have their constructors called before any other interaction (AFAIK). I understand that it is difficult to understand how many people may be relying on this "feature" and that changing the behavior would probably have to be supported through an option for backward compatibility. My issue was not with the constructor throwing an error, it was with the property setter assuming the state of the object was initialized and valid (the specific code is not shown in the example). |
I think that would fail if you had something like this: class MyController {
private _min : number = 0;
constructor() { }
} The resulting JS automatically sets _min in the constructor function: var MyController = (function () {
function MyController() {
this._min = 0;
}
return MyController;
}()); |
I appreciate people are taking time out to provide workarounds; however, I'm not really looking for a work around; to be frank, its a trivial issue to resolve and I probably shouldn't be writing Javascript if I can't workaround it:). I'm simply here to report the bug, which I still class as a bug. An APIs success is measured on its consistency. Every special case goes against this; an effects productivity, controllers in angular everywhere else are dealt with as types (with constructors), they are not functions. |
As docs says in: https://docs.angularjs.org/api/ng/service/$compile :
May be it should be changed ASAP. ¿Is there any scheduled change yet? |
@drpicox Thanks for finding that; it sounds like the API is going to change to be consistent, as you say; the only question is when? |
While I agree with this idea in principle, you do also have to keep in mind that while the change is trivial, it's also potentially massively breaking for any historical code that uses assignments within the constructor; That deprecation was introduced in 1.5, so I would expect that a breaking change of this magnitude would not be made until 1.6 or even 1.7 (Should really be in a major version, but Angular2 kinda killed that possibility it seems like without causing massive confusion). I haven't though about this for more than 15 seconds (quite literally), but another interesting idea would be that if a controller lacks on |
I haven't thought about it for more than 15 seconds either (quite literally), but I think this would break the expectation that all controllers are initialized when |
I get a thought to this "issue", and I think that may be there is a mid-way between break compatibility or do interfere in the use some ES5 features (like getters and setters). There are some examples in angular, that because some reason a breaking change is introduced, but there is a possible configuration that enables old/new behaviour. For example:
So, it might be something like this would be an option: $compileProvider.bindToControllerBeforeConstructor(false); and change the default in later versions. |
As @dpogue points out, this behavior breaks a common pattern (default true and binding to false). This "feature" irrevocably breaks the understanding of how constructors work. I continue to fail to see how binding properties to an instance is a sensible operation when, by definition, the instance is in an undefined state before a constructor finishes executing. A reasonable flow would be [constructor(), bindings, $onInit]. |
Thanks for your feedback everyone. Here is a little more context (which will hopefully give better perspective of the situation):
It will make more sense if you stop thinking were we are and focus on how we got there and how to get out of there 😃 How did we get here?
How do we get out of here? Things have changed and we do now have the means to get out (thanks to controller lifecycle hooks). Still we should get out of there without breaking all these apps that are currently (reluctantly or not) relying on this "feature". So, here is the general plan (there are still some details to figure out):
tl;dr In defense of the "feature", I believe it has served us very well and we would have been in a worse situation without it - but it's time for it to go now 😃 |
This is not strictly related to ES6, but I also use ES5 Object property getter/setters that expose "private" values and have a similar issue. Here's an excerpt:
|
Was the option to opt-out included? There is no preAssignBindingsEnabled-function in $compileProvider in v.1.5.9. |
@emillunde, we had to cut an interim 1.5.9 release that contains mostly security fixes. This feature will be included in 1.5.10 (which should be released pretty soon). |
@gkalpak - Just to confirm, does this change introduced in 1.6 just delay the assignment of Please let me know if you need me to clarify the question. |
@ashclarke, exactly.
|
Note: for support questions, please use one of these channels: https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#question. This repository's issues are reserved for feature requests and bug reports.
BUG
When using bindToController properties are being set before the constructor is invoked.
https://plnkr.co or similar (you can use this template as a starting point: http://plnkr.co/edit/tpl:yBpEi4).
Constructor should be called before properties are set.
Behaviour in properties setters that rely on values initialized in the constructor fail.
versions of Angular? Please also test with the latest stable and snapshot versions.
Windows 7, TypeScript 1.8.2, chrome 49.0.2623.87, Angular 1.5.0
The text was updated successfully, but these errors were encountered: