-
Notifications
You must be signed in to change notification settings - Fork 3.4k
fix(compiler): remove dependency on AngularJS private API #11320
Conversation
531bf90 to
0f7df0a
Compare
| * `$compileProvider.preAssignBindingsEnabled()` no longer exists. | ||
| * | ||
| * The default value is `false` but will change to `true` in AngularJS Material 1.2. | ||
| * The default value is `false` in to AngularJS 1.6 and earlier but `true` in AngularJS 1.7. |
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.
in to AngularJS 1.6 -> in AngularJS 1.6
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.
Also, the info that the default will change to true (for all AngularJS versions) in Material 1.2 was useful as well, I think it should stay here.
| // TODO change it to `true` in Material 1.2. | ||
| var respectPreAssignBindingsEnabled = false; | ||
| var respectPreAssignBindingsEnabled; | ||
| if (angular.version.major === 1 && angular.version.minor === 7) { |
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.
=== 7 -> >= 7.
| respectPreAssignBindingsEnabled = false; | ||
| } | ||
| this.respectPreAssignBindingsEnabled = function(respected) { | ||
| if (!respected && angular.version.major === 1 && angular.version.minor === 7) { |
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.
=== 7 -> >= 7
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 !respected check means you'll catch a getter as well so this API won't work at all in 1.7. The error message suggests you meant to add this error for the setter, not a getter. The getter is probably fine.
IOW, this should be moved to inside the if (angular.isDefined(respected)) block.
| this.respectPreAssignBindingsEnabled = function(respected) { | ||
| if (!respected && angular.version.major === 1 && angular.version.minor === 7) { | ||
| throw new Error( | ||
| 'Disabling respectPreAssignBindingsEnabled is not supported in AngularJS 1.7.'); |
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.
AngularJS 1.7 -> AngularJS >= 1.7.
| angular.extend(invokeCtrl.instance, locals); | ||
| } | ||
| var ctrl; | ||
| if (angular.version.major === 1 && angular.version.minor === 7) { |
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.
=== 7 -> >= 7.
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.
Unfortunately, you need to check for 1.7.1 here. In 1.7.0 the options.controllerAs should be the 4th argument 😒
(It is still OK if you don't support pre-assigning in 1.7.0 so that material bahaves consistently with all 1.7+ versions, but you need to call $controller differently on 1.7.0 vs 1.7.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.
controllerAs is an internal parameter, isn't it? Is there a way to stop relying on it?
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 should be possible. It is only used for assigning the controller instance onto locals.$scope. It could be done manually with injectLocals.$scope[options.controllerAs] = <instance>.
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.
That seems like a better way to do it.
|
|
||
| [ | ||
| var bindingStatesToTest; | ||
| if (angular.version.major === 1 && angular.version.minor === 7) { |
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.
=== 7 -> >= 7.
| if (angular.version.major === 1 && angular.version.minor === 7) { | ||
| respectPreAssignBindingsEnabled = true; | ||
| } else { | ||
| respectPreAssignBindingsEnabled = 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.
You can shorten that if you want:
var respectPreAssignBindingsEnabled = angular.version.major === 1 && angular.version.minor >= 7;2918cc9 to
a96abb5
Compare
|
I believe that all of the feedback has been addressed. Tests still look good against 1.7.0 and 1.7.1. PTAL. |
gkalpak
left a comment
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 respectPreAssignBindingsEnabled() docs mention:
If disabled (
false), the compiler assigns the value of each of the bindings to the properties of the controller object before the constructor of this object is called.
This isn't true for 1.7. Maybe this should be mentioned in the docs.
Other than that LGTM 👍
mgol
left a comment
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 left some more comments (it's almost there for me, though!).
| if (getPreAssignBindingsEnabled() && options.bindToController) { | ||
| angular.extend(invokeCtrl.instance, locals); | ||
| var ctrl; | ||
| if ((angular.version.major === 1 && angular.version.minor === 7 && angular.version.dot >= 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.
I don't think you have to check for >= 1.7.1 now that internal API usage is completely removed (i.e. the controllerAs parameter is no longer passed).
This can be changed to just angular.version.major === 1 && angular.version.minor >= 7 as in other places.
Am I right, @gkalpak?
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.
Right 👍
| * | ||
| * The default value is `false` but will change to `true` in AngularJS Material 1.2. | ||
| * The default value is `false` in AngularJS 1.6 and earlier but `true` in AngularJS 1.7. | ||
| * It is planned to change this to always default to `true` in AngularJS Material 1.2. |
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.
Saying that the default is true in AngularJS 1.7 suggests it can be changed, especially that the docs nowhere say that you can't change it.
Also, AngularJS 1.7 -> AngularJS 1.7 or later.
How about something like:
In AngularJS 1.7 or later the value is hardcoded to `true`. In AngularJS 1.6 and earlier
it's `false` by default. It is planned to change this to always default to `true` in
AngularJS Material 1.2.
|
|
||
| [ | ||
| var bindingStatesToTest; | ||
| if (angular.version.major === 1 && angular.version.minor >= 7) { |
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.
That's not 100% necessary but a test checking the respectPreAssignBindingsEnabled setter throws in 1.7 would be awesome.
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 gave it a shot, but I'm not sure how to test an exception in a module config function and calling it outside of that isn't allowed (not a function).
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 may be doable, the main problem is it's not possible to call module (which is used in tests to access the config phase) after inject was called at least once. You'd have to move inject from beforeEach of it blocks so that at the beginning of a new it you can still call:
module(function ($mdCompilerProvider) {
expect(function () {
$compileProvider.preAssignBindingsEnabled(false);
}).toThrow();
});I'm not 100% sure if an error thrown during the config phase doesn't break the test infrastructure but maybe it doesn't.
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.
You can test that it throws with something like:
it('should throw ...', () => {
module('material.core', $mdCompilerProvider =>
$mdCompilerProvider.respectPreAssignBindingsEnabled(false));
expect(inject).toThrowError(regexThatMatchesTheErrorMessage);
});OR
it('should throw ...', () => {
let provider;
module('material.core', $mdCompilerProvider => { provider = $mdCompilerProvider; });
inject();
expect(() => provider.respectPreAssignBindingsEnabled(false)).
toThrowError(regexThatMatchesTheErrorMessage);
});(Note: If you don't call inject(), config blocks will not be run.)
a96abb5 to
50a8820
Compare
This can still break an app, though. |
|
Right, but it's a breaking change in AngularJS 1.7, so they can keep AngularJS on 1.6.x or they can refactor their app. If they only upgrade AngularJS Material (and not AngularJS), then they shouldn't see anything break. Am I missing something here? |
This is debatable 😁 AngularJS removed There are two ways to look at things:
I think (2) would be better (aligning It is a grey area 😃 Possible scenario:
(Again, this is very open to interpretation. E.g. based on peerDependency ranges, one shouldn't be using 1.7.x yet, etc.) |
To add to that: if one used a version of Material that doesn't officially support AngularJS 1.7 and then performs a patch-level update of Material and the app breaks because pre-assigning is gone then IMO it's not technically a breaking change as they were using an unsupported configuration. That is, unless there is a version of Material 1.1.x that officially supports AngularJS 1.7.0 - then this PR would definitely be a breaking change in Material so shouldn't land in 1.1.x. EDIT: I see @gkalpak has already said something like that, I just expanded on it a little. |
|
It was said in a different PR, but preAssignBindings has been reverted and is now back in AngularJS 1.7.2 |
|
@jpike88, to be clear, preAssignBindings have not been reverted in AngularJS. I.e. AngularJS 1.7.x does not support pre-assigning bindings on components and directives that are compiled through the built-in What was reverted, were some internal, private APIs (no longer used by AngularJS itself), that are used by AngularJS Material to implement pre-assigning bindings in their |
d7beae2 to
bae289e
Compare
|
As @mgol mentioned, there is no current version of AngularJS Material that officially supports AngularJS 1.7.x. AngularJS Material 1.1.10 will be the first version that supports it. Our current documentation (1.1.9) for
That is the recommended configuration, but it only covers half of the options. If
So it seems like we need to support this |
Deprecating it is tricky as this means you're discouraging people from using it - and not using it means having the default of I guess you can deprecate setting it to |
|
@mgol good point, we can't use
With the following:
|
bae289e to
bc06844
Compare
|
PR updated, description in OP updated, commit msg updated. PTAL. |
mgol
left a comment
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.
One remark.
| // `invokeCtrl()`. However, when the controller is an ES6 class, `invokeCtrl.instance` is a | ||
| // *different instance* from `invokeCtrl()`. | ||
| var invokeCtrl = this.$controller(options.controller, injectLocals, true, options.controllerAs); | ||
| var invokeCtrl = this.$controller(options.controller, injectLocals, true); |
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.
Could you switch the logic to not pass the third parameter if getPreAssignBindingsEnabled() === false? This would be safer as in the recommended usage no private API would be used.
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.
Good call. I think it makes the 1.2.0 update more straightforward as well.
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.
PTAL and let me know if I missed anything.
bc06844 to
401599c
Compare
mgol
left a comment
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.
LGTM, good job!
| } | ||
|
|
||
| if (!getPreAssignBindingsEnabled() && options.bindToController) { | ||
| if (!preAssignBindingsEnabled && options.bindToController) { |
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.
Nit: this could be moved inside the the else block above.
remove one of two uses of private/undocumented arguments to $controller mark setting `respectPreAssignBindingsEnabled(false)` as deprecated update documentation add AngularJS 1.5.x back to TravisCI update AngularJS devDependencies to `^1.7.2` Closes #11319
401599c to
3ebf6cb
Compare
remove one of two uses of private/undocumented arguments to $controller mark setting `respectPreAssignBindingsEnabled(false)` as deprecated update documentation add AngularJS 1.5.x back to TravisCI update AngularJS devDependencies to `^1.7.2` Closes #11319
PR Checklist
Please check that your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
MdCompilerService._createControlleruses two private and undocumented AngularJS APIs (on$controller).Some of the docs for
respectPreAssignBindingsEnabledis confusing or incomplete.Issue Number:
Closes #11319
What is the new behavior?
respectPreAssignBindingsEnabled(false)as deprecated^1.7.2Does this PR introduce a breaking change?
Other information