Skip to content
This repository has been archived by the owner on Aug 29, 2023. It is now read-only.

fix(compiler): respect preAssignBindingsEnabled state #10469

Closed

Conversation

devversion
Copy link
Member

@devversion devversion commented Mar 7, 2017

  • The $mdCompiler now respects the preAssignBindingsEnabled state when using AngularJS 1.6 or higher.

BREAKING CHANGE

Developers that are upgrading from AngularJS 1.5 to AngularJS 1.6 may run into issues with their custom controllers.

All custom controllers that are are being used inside of Material components, like in the $mdDialog or $mdToast, can be affected.

Limited to controllers that are used in combination with the bindToController and locals option.

Angular Material starts respecting the preAssignBindingsEnabled state when using AngularJS 1.6+

This will mean that bindings are no longer initialized at constructor time.

$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.
}

To provide consistency, Angular Material components with custom controllers now work with the $onInit lifecycle hook (no other lifecycle hooks)

Fixes #10016

@devversion devversion added the needs: review This PR is waiting on review from the team label Mar 7, 2017
@googlebot googlebot added cla: yes PR author has signed Google's CLA: https://opensource.google.com/docs/cla/ labels Mar 7, 2017
@ThomasBurleson ThomasBurleson added this to the 1.1.4 milestone Mar 7, 2017
@ThomasBurleson ThomasBurleson added P0 - Presubmit First in progress Mainly for in progress PRs, but may be used for issues that require multiple PRs needs: review This PR is waiting on review from the team and removed needs: review This PR is waiting on review from the team P0 - Presubmit First labels Mar 7, 2017
@ThomasBurleson
Copy link
Contributor

@devversion - Think this one of my favorite PRs for Q1 2017. 🥇

@mgol
Copy link
Member

mgol commented Mar 7, 2017

The Karma not logging issue is a regression: karma-runner/karma#2582. How about locking Karma to 1.4 for now as it's not clear for now how they will resolve the issue and removing the workaround?

$provide.constant('$$mdPreAssignBindings',
// For Angular versions that do not support `preAssignBindingsEnabled`, always pre-assign the
// bindings.
$compileProvider.preAssignBindingsEnabled ? $compileProvider.preAssignBindingsEnabled() : true
Copy link
Member

@mgol mgol Mar 7, 2017

Choose a reason for hiding this comment

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

Are we sure the $compileProvider.preAssignBindingsEnabled() output is set in stone at this point?

Also, note that AngularJS 1.7 will remove $compileProvider.preAssignBindingsEnabled and the bindings will stop being pre-assigned so this code is not future-proof.

If the method is not present, it's safer to check the library version and set true only if it's older than 1.6.

Copy link
Member

Choose a reason for hiding this comment

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

Are we sure the $compileProvider.preAssignBindingsEnabled() output is set in stone at this point?

As a matter of fact, it is never set in stone 😁 (you can change it any time). Not that this is a common usecase.

.provider('$$mdPreAssignBindings', function ($compileProvider) {
  var hardcodedValue = (angular.version.major === 1 && angular.version.minor < 6) ? true : false;
  var getValue = $compileProvider.preAssignBindingsEnabled ?
    function () { $compileProvider.preAssignBindingsEnabled(); } :
    function () { return hardcodedValue; };

  this.$get = function () { return getValue; };  
})

Copy link
Contributor

Choose a reason for hiding this comment

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

Uugh.

Copy link
Member

Choose a reason for hiding this comment

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

@gkalpak your implementation is good, I'd just drop the ? true : false part as it's redundant here.

Copy link
Member

Choose a reason for hiding this comment

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

I do this true/false thing too often 😃

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.

🎉 💯

$provide.constant('$$mdPreAssignBindings',
// For Angular versions that do not support `preAssignBindingsEnabled`, always pre-assign the
// bindings.
$compileProvider.preAssignBindingsEnabled ? $compileProvider.preAssignBindingsEnabled() : true
Copy link
Member

Choose a reason for hiding this comment

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

Are we sure the $compileProvider.preAssignBindingsEnabled() output is set in stone at this point?

As a matter of fact, it is never set in stone 😁 (you can change it any time). Not that this is a common usecase.

.provider('$$mdPreAssignBindings', function ($compileProvider) {
  var hardcodedValue = (angular.version.major === 1 && angular.version.minor < 6) ? true : false;
  var getValue = $compileProvider.preAssignBindingsEnabled ?
    function () { $compileProvider.preAssignBindingsEnabled(); } :
    function () { return hardcodedValue; };

  this.$get = function () { return getValue; };  
})


var ctrl = invokeCtrl();
// Create the specified controller instance.
var ctrl = self._createController(options, injectLocals);
Copy link
Member

Choose a reason for hiding this comment

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

Not directly related to this PR, but it seems that you are accidentally putting $element into locals. Essentially, locals and injectLocals are the same object, but this doesn't seem intentional (and indeed assigning $element to the controller instance seems strange).

Was it intentional?

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point.

}

TestController.prototype.$onInit = function() {
expect(this.name).toBe('Bob');
Copy link
Member

Choose a reason for hiding this comment

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

There is no verification that $onInit() is actually called.

Copy link
Contributor

Choose a reason for hiding this comment

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

What do you mean.

Copy link
Member

Choose a reason for hiding this comment

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

For example, for the constructor you check that called has been set to true, so you know that the constructor has been called (and the expectations it contains verified).
There is nothing similar for $onInit().

You could add expect('foo').toBe('bar') inside $onInit() and the test would not fail if $onInit() is never called. This means that the test may not catch some future regression.

Copy link
Member

Choose a reason for hiding this comment

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

That's why I like QUnit's assert.expect(number) so much but Jasmine has no equivalent.

A proper test here should also probably spy on $onInit (with calledThrough()) to ensure it's not skipped.

Copy link
Member

@mgol mgol left a comment

Choose a reason for hiding this comment

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

There are some issues to resolve indicated in comments. Otherwise, A good idea to abstract the $onInit logic until support for AngularJS <1.5.10 is dropped.

@devversion
Copy link
Member Author

@gkalpak @mgol @ThomasBurleson Updated the PR.

@devversion devversion removed the in progress Mainly for in progress PRs, but may be used for issues that require multiple PRs label Mar 8, 2017
});

it('disabled should assigns bindings after constructor', function() {
configureCompiler(false);
Copy link
Contributor

Choose a reason for hiding this comment

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

let's use:

var shouldPreAssign = false;
var isIntantiated = false;

configureCompiler(shouldPreAssign);

Copy link
Member Author

@devversion devversion Mar 8, 2017

Choose a reason for hiding this comment

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

What advantage does this have? I think the spec name and function parameter already explain that this changes the preAssignBindings behavior.

Copy link
Contributor

Choose a reason for hiding this comment

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

I had to search for how it was disabled. the configureCompiler(false) was not intuitive.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah I understand. How is setPreAssignBindings?

@ThomasBurleson ThomasBurleson added needs: presubmit and removed needs: review This PR is waiting on review from the team labels Mar 9, 2017
@ThomasBurleson
Copy link
Contributor

@devversion - please squash your commits.

var hasPreAssignState = !!$compileProvider.preAssignBindingsEnabled;

this.$get = function() {
return hasPreAssignState ? $compileProvider.preAssignBindingsEnabled() : fallbackValue;
Copy link
Member

Choose a reason for hiding this comment

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

This will not catch changes that will happend at runtime (which is theoretically possible, although highly improbable).

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah I intentionally did it that way. If users change it at runtime then I don't think this should be respected. Providers should be set at config phase.

function setPreAssignBindings(preAssignBindingsEnabled) {
module(function($compileProvider) {
$compileProvider.preAssignBindingsEnabled(preAssignBindingsEnabled);
})
Copy link
Member

Choose a reason for hiding this comment

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

Missing semicolon 😱


var ctrl = invokeCtrl();
// Create the specified controller instance.
var ctrl = self._createController(options, injectLocals, locals);
Copy link
Member

Choose a reason for hiding this comment

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

Currently, injectLocals and locals are the same object. I assume this a bug, but not directly related to (or introduced by) this PR.

Copy link
Member Author

Choose a reason for hiding this comment

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

In what way are those similar? injectLocals contains the $element DI token.

Copy link
Member

Choose a reason for hiding this comment

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

In the way that angular.extend(locals, {$element: ...}) extends locals with $element and then returns locals. So, injectLocals === locals. I assume the intended behavior was injectLocals = angular.extend({$element: ...}, locals) or injectLocals = angular.extend({}, locals, {$element: ...}).

return data;
}

it('enabled should assigns bindings at instantiation', function() {
Copy link
Member

@gkalpak gkalpak Mar 9, 2017

Choose a reason for hiding this comment

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

assigns --> assign

expect(isInstantiated).toBe(true);
});

it('disabled should assigns bindings after constructor', function() {
Copy link
Member

Choose a reason for hiding this comment

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

assigns --> assign

@ThomasBurleson
Copy link
Contributor

ThomasBurleson commented Mar 9, 2017

@devversion - please squash your commits and rebase from master.

@devversion
Copy link
Member Author

@ThomasBurleson Done.

@mgol
Copy link
Member

mgol commented Mar 9, 2017

@devversion did you see my comment regarding the Karma update? This one: #10469 (comment).

@ThomasBurleson
Copy link
Contributor

@mgol, @gkalpak - last review before presubmit ?

@devversion
Copy link
Member Author

I just saw that I need to make one adjustment for the tests. Ignore the failing test for review.

function PreAssignBindingsProvider($compileProvider) {
// To avoid breaking changes in Material, AngularJS Material will only respect the
// preAssignBindingsEnabled state in AngularJS 1.6.X and higher.
var respectPreAssignState = angular.version.major === 1 && angular.version.minor > 5;
Copy link
Member

Choose a reason for hiding this comment

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

This will break with AngularJS ~1.5.10 if the developer sets the preAssignBindingsEnabled flag to false.

What are the breaking changes mentioned in a comment?

Copy link
Member Author

Choose a reason for hiding this comment

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

Made some changes to it. See updated PR

var respectPreAssignState = angular.version.major === 1 && angular.version.minor > 5;

this.$get = function() {
return respectPreAssignState ? $compileProvider.preAssignBindingsEnabled() : true;
Copy link
Member

Choose a reason for hiding this comment

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

This will break in AngularJS 1.7+. We had a thread about it with @gkalpak suggesting an implementation that would work, what did happen with that? :)

Copy link
Member Author

Choose a reason for hiding this comment

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

The implementation did not cover the changes we discussed in our meeting. Also we don't want to re-check the preAssignBindingsEnabled state for each $mdCompiler call (as it returned a getValue function)

I changed it now to work as we discussed on our meeting

  • 1.5: Bindings will be always pre-assigned as same as with Material before.
  • 1.6: Angular Material will start respecting the preAssignBindingsEnabled state
  • 1.7: Compiler will always sets preAssignBindingsEnabled to false.

* The `$mdCompiler` now respects the `preAssignBindingsEnabled` state when using AngularJS 1.6 or higher.

**BREAKING CHANGE**

Developers that are upgrading from AngularJS 1.5 to AngularJS 1.6 may run into issues with their custom controllers.

All custom controllers that are are being used inside of Material components, like in the `$mdDialog` or `$mdToast`, can be affected.

> Limited to controllers that are used in combination with the `bindToController` and `locals` option.

Angular Material starts respecting the [`preAssignBindingsEnabled`](angular/angular.js#15352) state when using AngularJS 1.6+

This will mean that bindings are no longer initialized at `constructor` time.

```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.
}
```

To provide consistency, Angular Material components with custom controllers now work with the `$onInit` lifecycle hook (**no** other lifecycle hooks)

Fixes angular#10016
// To avoid that the preAssignBindings state causes issues when upgrading from AngularJS 1.5 to
// AngularJS 1.6, AngularJS Material will only respect the preAssignBindingsEnabled state in 1.6
var respectPreAssignState = angular.version.major === 1 && angular.version.minor === 6;
var fallbackValue = !!$compileProvider.preAssignBindingsEnabled;
Copy link
Member

Choose a reason for hiding this comment

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

As @mgol has pointed out, this will break in the future (most probably 1.7+). The plan is to remove the preAssingBindingsEnabled method and not support pre-assignement neither by default, nor as an opt-in (this is the PR btw: angular/angular.js#15782).

Base on what we have discussed in the last meeting, you need something like this:

var defaultPreAssignValue = angular.version.major === 1 && angular.version.minor < 6;
var respectPreAssignState = angular.version.major === 1 && angular.version.minor > 5 &&
                            $compileProvider.preAssignBindingsEnabled;

this.$get = function() {
  return respectPreAssingState ? $compileProvider.preAssignBindingsEnabled() : defaultPreAssignState;
};

Copy link
Member

Choose a reason for hiding this comment

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

BTW, the current implementation will also break in 1.5.0-1.5.9 (where there is no $compileProvider.preAssignBindingsEnabled method).

Copy link
Member

Choose a reason for hiding this comment

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

@gkalpak

BTW, the current implementation will also break in 1.5.0-1.5.9 (where there is no $compileProvider.preAssignBindingsEnabled method).

How so? fallbackValue will then be false but it won't be used anyway.

Copy link
Member

Choose a reason for hiding this comment

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

fallbackValue will be false and it will be used. respectPreAssignState would be false, so the (incorrect) fallback value will be used.

(To be clear, by "current implementation" I mean the implementation currently used in this PR.)

Copy link
Member Author

Choose a reason for hiding this comment

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

Well, I thought that preAssignBindingsEnabled has been added in 1.5.X and changed in 1.6 to false by default and will be removed in 1.7.

Copy link
Member

Choose a reason for hiding this comment

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

@gkalpak Ah, you're right.

@devversion The flag has been added in 1.5.9 which was released after a long wait and even after 1.6.0 was released. It's highly likely most of 1.5.x users will not have this flag available.

Copy link
Member

Choose a reason for hiding this comment

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

The fallback value should be defined based on AngularJS version, not the presence of the $compileProvider.preAssignBindingsEnabled flag.

Besides, as far as I understand, Material still supports AngularJS 1.3+, doesn't it?

function PreAssignBindingsProvider($compileProvider) {
// To avoid that the preAssignBindings state causes issues when upgrading from AngularJS 1.5 to
// AngularJS 1.6, AngularJS Material will only respect the preAssignBindingsEnabled state in 1.6
var respectPreAssignState = angular.version.major === 1 && angular.version.minor === 6;
Copy link
Member

Choose a reason for hiding this comment

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

About not respecting the flag in 1.5: it's about how MdCompilerService#_createController behaves so it will not break 1.5, it will just still preassign bindings in 1.5.10 even if the developer sets preAssignBindingsEnabled to false, I see it now.

We could have respected the flag in 1.5.10 if your PR from a while ago accounting for this flag wasn't merged before this one as it wouldn't be breaking then - no one would be using 1.5.10 with Material & this flag set to false as this configuration was broken.

I assume Material needs to ignore this flag because Material 1.1.3 works fine in 1.5.10 with this flag set to false? (Does it?)

Copy link
Member

Choose a reason for hiding this comment

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

BTW, just in case we'd have to revert the removal and defer it to 1.8, it would be safer to check for angular.version.minor > 5 instead of angular.version.minor === 6

Copy link
Member

@mgol mgol Mar 11, 2017

Choose a reason for hiding this comment

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

BTW, regarding the argument for not respecting the flag in ~1.5.10 but respecting in ~1.6 - if someone was using Material with AngularJS 1.6 and it worked for them as the components they used worked fine, this change may break them.

Maybe it would be safer to release this as 1.2.0, not 1.1.5 and then not ignoring the flag if it exists?

What do you think? @devversion @gkalpak @ThomasBurleson

Copy link
Member

Choose a reason for hiding this comment

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

if someone was using Material with AngularJS 1.6 and it worked for them as the components they used worked fine, this change may break them.

🤢 True.
It sounds like there is indeed no (reaconable) way to make this non-breaking (without making it opt-in - e.g. with an mdCompiler flag) 😞

function PreAssignBindingsProvider($compileProvider) {
// To avoid that the preAssignBindings state causes issues when upgrading from AngularJS 1.5 to
// AngularJS 1.6, AngularJS Material will only respect the preAssignBindingsEnabled state in 1.6
var respectPreAssignState = angular.version.major === 1 && angular.version.minor === 6;
Copy link
Member

Choose a reason for hiding this comment

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

BTW, just in case we'd have to revert the removal and defer it to 1.8, it would be safer to check for angular.version.minor > 5 instead of angular.version.minor === 6

@jelbourn
Copy link
Member

@mmalerba can you presubmit this (but don't merge it if it passes)?

@devversion devversion added the in progress Mainly for in progress PRs, but may be used for issues that require multiple PRs label Mar 17, 2017
@mmalerba
Copy link
Contributor

@jelbourn latest is good, v1_1 has ~10 failures (this is with merging this PR into master at the commit v1_1 is currently synced to)

@mgol
Copy link
Member

mgol commented Mar 27, 2017

Since there are edge cases that would break when this PR lands in its current state, I think we could do the following to not have to wait for Material 1.2 with landing it:

  1. Add a new public flag (sth like $mdCompilerProvider.respectPreAssignBindingsState(true|false)) that would make Material respect the value of AngularJS' $compilerProvider.preAssignBindingsEnabled().
  2. Make this flag false by default, turn it to true by default in 1.2.0, remove in 1.3.0. Optionally, the flag could be made a noop in Material 1.2.0 (and removed in 1.3.0) if we didn't want to keep this logic that long.
  3. Change the logic in the current PR to:
    1. If $mdCompilerProvider.respectPreAssignBindingsState() === false: always preassign bindings.
    2. If $mdCompilerProvider.respectPreAssignBindingsState() === true:
      1. If $compilerProvider.preAssignBindingsEnabled exist, preassign bindings if and only if it returns true.
      2. If it doesn't exist then:
        1. With AngularJS <1.6: preassign bindings.
        2. With AngularJS >=1.6: don't preassign bindings.

What do you think?

@ThomasBurleson ThomasBurleson added needs: presubmit and removed in progress Mainly for in progress PRs, but may be used for issues that require multiple PRs labels May 8, 2017
@ThomasBurleson
Copy link
Contributor

@mmalerba - Can you elaborate. I admit that I do not understand your response. Is this PR invalid for a presubmit? If yes, then why ?

@ThomasBurleson
Copy link
Contributor

@mgol - let's talk about your ideas offline in a call. Thx

@mmalerba
Copy link
Contributor

@ThomasBurleson there were 10 failures when I checked, which is a relatively small number and may include some that were just flakes. It can probably be merged with some shepherding from the caretaker

@ThomasBurleson ThomasBurleson added in progress Mainly for in progress PRs, but may be used for issues that require multiple PRs and removed needs: presubmit labels May 25, 2017
mgol added a commit to mgol/material that referenced this pull request Jun 8, 2017
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
Closes angular#10469
@mgol
Copy link
Member

mgol commented Jun 8, 2017

This PR evolved into PR #10726; PTAL.

@devversion
Copy link
Member Author

@mgol Thanks for continuing this. Closing my PR here.

@devversion devversion closed this Jun 8, 2017
mgol added a commit to mgol/material that referenced this pull request Jun 9, 2017
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
mgol added a commit to mgol/material that referenced this pull request Jun 21, 2017
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
mgol added a commit to mgol/material that referenced this pull request Jun 21, 2017
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
tinayuangao pushed a commit that referenced this pull request Aug 3, 2017
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 #10016
Ref #10469
Closes #10726
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
cla: yes PR author has signed Google's CLA: https://opensource.google.com/docs/cla/ in progress Mainly for in progress PRs, but may be used for issues that require multiple PRs
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants