-
Notifications
You must be signed in to change notification settings - Fork 3.4k
feat(compiler): respect preAssignBindingsEnabled state #10726
Conversation
1. The `$mdCompiler` is now able to respect the `preAssignBindingsEnabled` state when using AngularJS 1.5.10 or higher; to enable, invoke: $mdCompilerProvider.respectPreAssignBindingsEnabled(true); 2. `$mdCompiler` now understands the `$onInit` lifecycle hooks in controllers. Note that no other AngularJS 1.5+ lifecycle hooks are supported currently. Invoking: $mdCompilerProvider.respectPreAssignBindingsEnabled(true); will make bindings in Material custom components like `$mdDialog` or `$mdToast` only available in controller constructors if they are available in constructors of all other AngularJS controllers. By default this will happen in AngularJS 1.6 or newer. This can also be achieved with AngularJS >=1.5.10 <1.6.0 if: $compilerProvider.preAssignBindingsEnabled(false); is invoked. Example: ```js $mdDialog.show({ locals: { myVar: true }, controller: MyController, bindToController: true } function MyController() { // No locals from Angular Material are set yet. e.g myVar is undefined. } MyController.prototype.$onInit = function() { // Bindings are now set in the $onInit lifecycle hook. } ``` Huge thanks to Paul Gschwendtner (@devversion) for the initial draft version of this feature. Fixes angular#10016 Ref angular#10469 Closes angular#10726
* This method and the option to assign the bindings before calling the controller's constructor | ||
* will be removed in v1.3.0. | ||
*/ | ||
var 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.
Add a TODO comment about the default changing to true
in Material 1.2.
|
||
/** @private @const {!angular.$compile} */ | ||
this.$compile = $compile; | ||
// respectPreAssignBindingsEnabled === 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.
Add a comment that we're ignoring the AngularJS setting in this case.
[ | ||
{respectPreAssignBindingsEnabled: true}, | ||
{respectPreAssignBindingsEnabled: false}, | ||
{respectPreAssignBindingsEnabled: '"default"', equivalentTo: 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.
Add a comment about the Material 1.2 change.
|
||
beforeEach(function() { | ||
module(function($mdCompilerProvider) { | ||
console.log(angular.version, preAssignBindingsEnabledInAngularJS); |
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.
remove it
if (respectPreAssignBindingsEnabled && !preAssignBindingsEnabledInAngularJS) { | ||
it('$mdCompileProvider.preAssignBindingsEnabled should report bindings are not pre-assigned', function() { | ||
module(function($mdCompilerProvider) { | ||
expect($mdCompilerProvider.preAssignBindingsEnabled()).toBe(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.
It should be true
; why did the tests pass? I need to check that.
EDIT: I commented in a wrong place.
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.
Why should it be 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.
It shouldn't; I commented on a wrong line; fixed.
Nice catch!
|
||
}); | ||
|
||
[ |
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.
Add a test asserting that if bindToController
is set to false
the $onInit
method is called anyway.
* makes it hard to unit test Material Dialog/Toast controllers using the `$controller` helper as it always follows | ||
* the `$compileProvider.preAssignBindingsEnabled()` value. | ||
* | ||
* @deprecated |
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.
Remove the deprecated note (here & in other places if present).
* | ||
* This method will be removed in v1.3.0. | ||
*/ | ||
this.preAssignBindingsEnabled = 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.
Maybe we don't need this method to be public until someone needs 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.
Also, maybe change the name to indicate it's a getter? Like getPreAssignBindingsEnabled
.
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.
Nice 💯
if (respectPreAssignBindingsEnabled && !preAssignBindingsEnabledInAngularJS) { | ||
it('$mdCompileProvider.preAssignBindingsEnabled should report bindings are not pre-assigned', function() { | ||
module(function($mdCompilerProvider) { | ||
expect($mdCompilerProvider.preAssignBindingsEnabled()).toBe(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.
Why should it be true
?
/** @private @const {!angular.$q} */ | ||
this.$q = $q; | ||
MdCompilerProvider.$inject = ['$compileProvider']; | ||
/** @this */ |
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.
Is this necessary?
* @name $mdCompilerProvider#respectPreAssignBindingsEnabled | ||
* | ||
* @param {boolean=} enabled update the respectPreAssignBindingsEnabled state if provided, otherwise just return | ||
* the current mdPreAssignBindingsEnabled state |
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.
mdPreAssignBindingsEnabled --> respectPreAssignBindingsEnabled
* ](https://code.angularjs.org/1.6.4/docs/api/ng/provider/$compileProvider#preAssignBindingsEnabled) | ||
* for more information. | ||
* | ||
* If disabled (false), the compiler assigns the value of each of the bindings to the |
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.
disabled (false) --> enabled (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.
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.
😞 OK 😞
But I'll be back 😈
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.
Of course. I expect nothing less.
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.
@gkalpak What's wrong here? I think current text is OK and your proposed change is wrong...
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.
Yes, it seems correct now. Not sure what happened 😁
* @ngdoc method | ||
* @name $mdCompilerProvider#respectPreAssignBindingsEnabled | ||
* | ||
* @param {boolean=} enabled update the respectPreAssignBindingsEnabled state if provided, otherwise just return |
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.
enabled --> respect (?)
(Or was enabled
intntional?)
// For compatibility with AngularJS 1.6+, we should always use the $onInit hook in | ||
// interimElements. The $mdCompiler simulates the $onInit hook for all versions. | ||
this.$onInit = function() { | ||
var isPrompt = this.$type == 'prompt'; |
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.
Please use ===
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 is exactly the same code that was here before. I'd rather not change unrelated things in this PR.
The same applies to most of your other comments.
If you ignore whitespace-only changes (via appending ?w=1
to the URL: https://github.com/angular/material/pull/10726/files?w=1) you will only see what really changed in the logic.
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.
Yeah i understand.. thanks!
} | ||
|
||
this.hide = function() { | ||
$mdDialog.hide(isPrompt ? this.result : 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.
i think hide returns a promise so let's return it so it can be chainable
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.hide = function() {
return $mdDialog.hide(isPrompt ? this.result : true);
}
$mdDialog.hide(isPrompt ? this.result : true); | ||
}; | ||
this.abort = function() { | ||
$mdDialog.cancel(); |
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.
return here as well
}; | ||
this.keypress = function($event) { | ||
if ($event.keyCode === $mdConstant.KEY_CODE.ENTER) { | ||
$mdDialog.hide(this.result); |
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.
return here as well
and outside the if
return $q.resolve();
}); | ||
|
||
this.resolve = function() { | ||
$mdToast.hide( ACTION_RESOLVE ); |
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.
return here 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.
this.resolve = function() {
return $mdToast.hide( ACTION_RESOLVE );
}
module(function($mdCompilerProvider) { | ||
console.log(angular.version, preAssignBindingsEnabledInAngularJS); | ||
// Don't set the value so that the default state can be tested. | ||
if (realRespectPreAssignBindingsEnabled === true || realRespectPreAssignBindingsEnabled === 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.
cant we do angular.isDefined(realRespectPreAssignBindingsEnabled)
instead?
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.
Sure.
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 wonder why I didn't think about that having used exactly this method in source. :)
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 is why it hit me
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.
@mgol: Because you want to differentiate true
/false
from "default"
. angular.isDefined()
won't work here.
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.
Ah, that's why I didn't think about that. 😄
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.
What about
typeof(realRespectPreAssignBindingsEnabled) === 'boolean'
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 would work. As would realRespectPreAssignBindingsEnabled !== 'default'
.
} else { | ||
it('$mdCompileProvider.preAssignBindingsEnabled should report bindings are pre-assigned', function() { | ||
module(function($mdCompilerProvider) { | ||
expect($mdCompilerProvider.preAssignBindingsEnabled()).toBe(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.
It should be true
; why did the tests pass? I need to check that.
1. The `$mdCompiler` is now able to respect the `preAssignBindingsEnabled` state when using AngularJS 1.5.10 or higher; to enable, invoke: $mdCompilerProvider.respectPreAssignBindingsEnabled(true); 2. `$mdCompiler` now understands the `$onInit` lifecycle hooks in controllers. Note that no other AngularJS 1.5+ lifecycle hooks are supported currently. Invoking: $mdCompilerProvider.respectPreAssignBindingsEnabled(true); will make bindings in Material custom components like `$mdDialog` or `$mdToast` only available in controller constructors if they are available in constructors of all other AngularJS controllers. By default this will happen in AngularJS 1.6 or newer. This can also be achieved with AngularJS >=1.5.10 <1.6.0 if: $compilerProvider.preAssignBindingsEnabled(false); is invoked. Example: ```js $mdDialog.show({ locals: { myVar: true }, controller: MyController, bindToController: true } function MyController() { // No locals from Angular Material are set yet. e.g myVar is undefined. } MyController.prototype.$onInit = function() { // Bindings are now set in the $onInit lifecycle hook. } ``` Huge thanks to Paul Gschwendtner (@devversion) for the initial draft version of this feature. Fixes angular#10016 Ref angular#10469 Closes angular#10726
@ThomasBurleson @EladBezalel @gkalpak PR updated, comments addressed. |
I've tested this with one of my company's internal apps and at first sight everything seemed to work with I've also run tests on default settings and everything seemed to work without any modifications. There's one last thing to resolve - @jbedard & @gkalpak mentioned that exposing |
1. The `$mdCompiler` is now able to respect the `preAssignBindingsEnabled` state when using AngularJS 1.5.10 or higher; to enable, invoke: $mdCompilerProvider.respectPreAssignBindingsEnabled(true); 2. `$mdCompiler` now understands the `$onInit` lifecycle hooks in controllers. Note that no other AngularJS 1.5+ lifecycle hooks are supported currently. Invoking: $mdCompilerProvider.respectPreAssignBindingsEnabled(true); will make bindings in Material custom components like `$mdDialog` or `$mdToast` only available in controller constructors if they are available in constructors of all other AngularJS controllers. By default this will happen in AngularJS 1.6 or newer. This can also be achieved with AngularJS >=1.5.10 <1.6.0 if: $compilerProvider.preAssignBindingsEnabled(false); is invoked. Example: ```js $mdDialog.show({ locals: { myVar: true }, controller: MyController, bindToController: true } function MyController() { // No locals from Angular Material are set yet. e.g myVar is undefined. } MyController.prototype.$onInit = function() { // Bindings are now set in the $onInit lifecycle hook. } ``` Huge thanks to Paul Gschwendtner (@devversion) for the initial draft version of this feature. Fixes angular#10016 Ref angular#10469 Closes angular#10726
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
Looks like this succeeds on google presubmit |
The
$mdCompiler
is now able to respect thepreAssignBindingsEnabled
statewhen using AngularJS 1.5.10 or higher; to enable, invoke:
$mdCompilerProvider.respectPreAssignBindingsEnabled(true);
$mdCompiler
now understands the$onInit
lifecycle hooks in controllers.Note that no other AngularJS 1.5+ lifecycle hooks are supported currently.
Invoking:
will make bindings in Material custom components like
$mdDialog
or$mdToast
only available in controller constructors if they are available in constructors
of all other AngularJS controllers. By default this will happen in AngularJS
1.6 or newer. This can also be achieved with AngularJS >=1.5.10 <1.6.0 if:
is invoked.
Example:
Huge thanks to Paul Gschwendtner (@devversion) for the initial draft version of
this feature.
Fixes #10016
Fixed #10377
Ref #10469
NOTE: I'm marking this PR as WIP as I still want to test it manually with some real code to ensure there's nothing left to do. I also need to think if there's something else I need to test here.