-
Notifications
You must be signed in to change notification settings - Fork 27.5k
$controller cannot instantiate ES6 classes #12614
Comments
See comment on linked PR: #12614 is not fixed by this – $controller uses $injector, but bindToController has its own logic to instantiate controllers on directives. I'm not sure it'll be possible to fix bindToController, it's way of instantiating a class on top of an existing object, then applying the ctor to it might be inherently incompatible with ES6. |
@mprobst It's not just an ES6 issue. The bindToController implementation is also incompatible with ES5, ES3 ... JavaScript, period, because no action is taken to carry the prototype of the original constructor over to the artificial target. Turning on "bindToController" will break any controller in any version of JS if it makes use of its prototype. I haven't dug deep into the code there yet, but it seems like this could be (more or less) fixed simply by having the artificial target begin as Also, the behavior they want to achieve can be implemented like this (in its desugared ES5 version):
|
@bathos , ooc could you provide an example. It has worked for me in the past for simple cases (I think), but I haven't extensively used prototype chains in directive controllers tbh. |
Isn't that exactly what's happening in controller.js#L128-L130 ? |
@gkalpak Yes, that does look sound. But is that actually what's happening when bindToController is in play? @mprobst's comment made it seem that that was not the case, and in my case, controllers are only affected if bindToController is used. That said, I also haven't tried it with generalized test cases and couldn't say for sure yet that there aren't local factors in the results I've seen. |
I think @mprobst's comment was about ES6 classes, not "plain" constructor functions.
I would be still curious to take a look at those examples, if you can post them in CodePen, Plnkr etc. |
@gkalpak Sorry not to follow up sooner, but also because I was rather emphatic about something which wasn't really true. (It really looked like it was, though!) The problem I was encountering stemmed from the fact that in my own code, I had a class decorator that essentially did the same thing, but made incorrect assumptions about how Angular would consume the class. It was an injection decorator that aggregated injections on $inject and then generated a one-off class per instantiation whose prototype it augmented with the injections as properties (for easy in-method access and no overlong constructor signature) before returning that new instance. After tweaking its implementation, everything did fall into place, and I shouldn't have expected Angular to like the way I was doing it initially. |
@bathos, np 😃 I'm glad that everything fell into place after all ! Let's see if we can find a way to support ES6 classes (if at all possible)... |
@gkalpak, what part of it isn't working now? I am successfully using es6 classes with bindToController in 1.4 now that I've found my own error. It seems to be instantiating them correctly. |
Is that so ? That's unexpected (by me at least). Are you using native classes (i.e. no transpiling to ES5 or something) ? |
Non-native, but with Babel 5, whose transpiled classes include an instantiation vs invocation check. That non-native check could be worked around (e.g. However, I don't think that's what's being done. It looks like controllers with bindToController do eventually pass through $inject.instantiate (now, anyway) which does this:
The clever use of applying bind there is needed since the length of args is unknown; nonetheless, this is a genuine instantiation. Am I missing something where the btc controller gets in trouble along the way? |
@bathos, the So, atm |
To recap: In order for |
Ah, I missed the other pathway. Makes sense: the |
Tested using
|
This has indeed been fixed by #12598 and #13682 (and followup PRs). |
ES6 classes can only be instantiated using
new
.$controller
uses$injector
to instantiate the classes which even after this fix: #12598 uses fn.apply.In particular, this should work when bindToController is used.
The text was updated successfully, but these errors were encountered: