Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

refactor($compile): remove preAssignBindingsEnabled leftovers #16580

Closed
wants to merge 1 commit into from

Conversation

thorn0
Copy link
Contributor

@thorn0 thorn0 commented May 26, 2018

Now that we don't need to support preAssignBindingsEnabled (removed in #15782), complexity introduced in $controller by #7645 can be removed.

return fn.apply(self, args);
} else {
if (isClass(fn)) {
// This code path was used by $controller previously and is not really needed any more.
Copy link
Contributor Author

@thorn0 thorn0 May 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove these hacks? Or would it be considered a breaking change in the public API? This behavior of invoke isn't documented.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since fn is documented to be a function (not a class) and it doesn't make sense to call invoke on a class, it is fine to remove this imo.

@thorn0 thorn0 force-pushed the refactor-compile branch 2 times, most recently from 6b9a0fc to 219c0f0 Compare May 26, 2018 13:08
Copy link
Member

@gkalpak gkalpak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally LGTM.
I was surprized that no tests needed to be changed/removed.

return fn.apply(self, args);
} else {
if (isClass(fn)) {
// This code path was used by $controller previously and is not really needed any more.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since fn is documented to be a function (not a class) and it doesn't make sense to call invoke on a class, it is fine to remove this imo.

@@ -81,16 +81,12 @@ function $ControllerProvider() {
* It's just a simple call to {@link auto.$injector $injector}, but extracted into
* a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
*/
return function $controller(expression, locals, later, ident) {
return function $controller(expression, locals, _ignored, ident) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Theoretically, we can do whatever we want with "private", undocumented params 😁

// If true, $controller will allocate the object with the correct
// prototype chain, but will not invoke the controller until a returned
// callback is invoked.
// param `_ignored` --- not used, kept for compatibility with the $controller decorator in ngMock
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why keep the unused param and not change the decorated ngMock $controller?

var require = controllerDirective.require;
if (controllerDirective.bindToController && !isArray(require) && isObject(require)) {
extend(elementControllers[name].instance, getControllers(name, require, $element, elementControllers));
var instance = $controller(controllerConstructor, locals, false, directive.controllerAs);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One difference with the previous implementation is that all controller instances where available on the element before instantiating a controller. (Now it depends on the relative order of controllers.)
But I think this is fine since it is not recommended to access controllers directly off of $element, but require them and access them in ngOnInit().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'Instances available before instantiation` is exactly what we're getting rid of.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really 😁

First of all, this is a refactoring commit, so we shouldn't be getting rid of anything 😛
The associated, feature-removing PR got rid of bindings (and instances?) being assigned to the controller instance before instantiation. But if someone tried to grab the instances with $element.controller('xyz'), they would be there (possibly uninstantiated, but that doesn't matter).

So, one could argue that this commit introduces a breaking change. But like I said, "I think this is fine since it is not recommended to access controllers directly off of $element, but one should require them and access them in ngOnInit()". 😃

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they would be there (possibly uninstantiated, but that doesn't matter)

And only if the class isn't an ES6 class.

@thorn0
Copy link
Contributor Author

thorn0 commented May 28, 2018

@gkalpak I've addressed all the comments. Please have a look.

@thorn0 thorn0 force-pushed the refactor-compile branch from 95fdaf4 to 342ab1e Compare May 28, 2018 08:41
Copy link
Member

@gkalpak gkalpak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM as soon as Travis is happy 👍

@thorn0 thorn0 force-pushed the refactor-compile branch 2 times, most recently from 162ba2c to a88048f Compare May 29, 2018 06:58
@thorn0
Copy link
Contributor Author

thorn0 commented May 29, 2018

Travis's unhappiness seems to be unrelated to my changes.

@Narretz
Copy link
Contributor

Narretz commented May 30, 2018

I think the minor concerns in this comment chain: #16580 (comment) should be included in some form in the commit message. In the off chance that this affects someone, it makes it easier to recap what happened.
Would this change affect people that access the controller of another directive in a directive controller? I assume the bindings are not initialized anyway, so it shouldn't make a difference.

@thorn0 thorn0 force-pushed the refactor-compile branch from a88048f to 510a2b5 Compare May 30, 2018 10:39
@thorn0
Copy link
Contributor Author

thorn0 commented May 30, 2018

@Narretz Ok, added it.

Would this change affect people that access the controller of another directive in a directive controller

If those people access other controllers via $element.controller(...) (or directly via .data(...)) from a controller constructor and don't use ES2015 classes, then yes. However, why would anyone do it? Nobody promised it would work. It's not a documented use case.

Now that we don't need to support `preAssignBindingsEnabled` (removed in angular#15782),
complexity introduced in `$controller` by angular#7645 can be removed.

One difference with the previous implementation is that all non-ES2015-class controller instances
were available on the element before calling their constructors. Now it depends on the relative
order of controllers. Controller constructors shouldn't be used to access other controllers
(e.g. via `$element.controller(directiveName)`). The recommended way is to use the `require`
property of the directive definition object and the life cycle hooks `$onChanges` or `$onInit`.

See
https://docs.angularjs.org/api/ng/service/$compile#-require-
https://docs.angularjs.org/api/ng/service/$compile#life-cycle-hooks
@thorn0 thorn0 force-pushed the refactor-compile branch from 510a2b5 to 2ee9dc2 Compare May 30, 2018 12:43
@Narretz
Copy link
Contributor

Narretz commented May 30, 2018

Well, .controller() is a documented function on the jqlite element. Now if access to the controller instance in the constructor should be possible is probably a grey area. However, the issue #5893 was concluded with the option to bind controllers directly to another controller instance, so I think we are good here.

Copy link
Contributor

@Narretz Narretz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve, but we need to be prepared that some people have been requiring the controllers via element in the constructor. ;)

@gkalpak gkalpak closed this in 8e104ee May 30, 2018
gkalpak pushed a commit that referenced this pull request May 30, 2018
Now that we don't need to support `preAssignBindingsEnabled` (removed in #15782),
complexity introduced in `$controller` by #7645 can be removed.

One difference with the previous implementation is that all non-ES2015-class controller instances
were available on the element before calling their constructors. Now it depends on the relative
order of controllers. Controller constructors shouldn't be used to access other controllers
(e.g. via `$element.controller(directiveName)`). The recommended way is to use the `require`
property of the directive definition object and the life cycle hooks `$onChanges` or `$onInit`.

See
https://docs.angularjs.org/api/ng/service/$compile#-require-
https://docs.angularjs.org/api/ng/service/$compile#life-cycle-hooks

Closes #16580
@thorn0 thorn0 mentioned this pull request Jun 8, 2018
2 tasks
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants