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

Commit a96abb5

Browse files
committed
fix(compiler): resolve breaking changes in AngularJS 1.7.1
remove use of private and undocumented arguments to $controller update how preAssignBindingsEnabled is handled for AngularJS 1.7+ Fixes #11319
1 parent 0046467 commit a96abb5

File tree

4 files changed

+87
-60
lines changed

4 files changed

+87
-60
lines changed

package-lock.json

Lines changed: 24 additions & 24 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,14 @@
2121
"scss": "./dist/angular-material.scss",
2222
"devDependencies": {
2323
"add-stream": "^1.0.0",
24-
"angular": "^1.5.0",
25-
"angular-animate": "^1.5.0",
26-
"angular-aria": "^1.5.0",
27-
"angular-messages": "^1.5.0",
28-
"angular-mocks": "^1.5.0",
29-
"angular-route": "^1.5.0",
30-
"angular-sanitize": "^1.5.0",
31-
"angular-touch": "^1.5.0",
24+
"angular": "^1.7.0",
25+
"angular-animate": "^1.7.0",
26+
"angular-aria": "^1.7.0",
27+
"angular-messages": "^1.7.0",
28+
"angular-mocks": "^1.7.0",
29+
"angular-route": "^1.7.0",
30+
"angular-sanitize": "^1.7.0",
31+
"angular-touch": "^1.7.0",
3232
"angularytics": "^0.4.0",
3333
"canonical-path": "0.0.2",
3434
"cli-color": "^1.0.0",

src/core/services/compiler/compiler.js

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ function MdCompilerProvider($compileProvider) {
124124
* - `>=1.7` - the compiler calls the constructor first before assigning bindings and
125125
* `$compileProvider.preAssignBindingsEnabled()` no longer exists.
126126
*
127-
* The default value is `false` but will change to `true` in AngularJS Material 1.2.
127+
* The default value is `false` in AngularJS 1.6 and earlier but `true` in AngularJS 1.7.
128+
* It is planned to change this to always default to `true` in AngularJS Material 1.2.
128129
*
129130
* It is recommended to set this flag to `true` in AngularJS Material 1.1.x. The only reason
130131
* it's not set that way by default is backwards compatibility. Not setting the flag to `true`
@@ -133,10 +134,13 @@ function MdCompilerProvider($compileProvider) {
133134
* Material Dialog/Panel/Toast/BottomSheet controllers using the `$controller` helper
134135
* as it always follows the `$compileProvider.preAssignBindingsEnabled()` value.
135136
*/
136-
// TODO change it to `true` in Material 1.2.
137-
var respectPreAssignBindingsEnabled = false;
137+
var respectPreAssignBindingsEnabled = angular.version.major === 1 && angular.version.minor >= 7;
138138
this.respectPreAssignBindingsEnabled = function(respected) {
139139
if (angular.isDefined(respected)) {
140+
if (!respected && angular.version.major === 1 && angular.version.minor >= 7) {
141+
throw new Error(
142+
'Disabling respectPreAssignBindingsEnabled is not supported in AngularJS 1.7 or later.');
143+
}
140144
respectPreAssignBindingsEnabled = respected;
141145
return this;
142146
}
@@ -444,27 +448,38 @@ function MdCompilerProvider($compileProvider) {
444448

445449
/**
446450
* Creates and instantiates a new controller with the specified options.
447-
* @param {!Object} options Options that include the controller
451+
* @param {!Object} options Options that include the controller function or string.
448452
* @param {!Object} injectLocals Locals to to be provided in the controller DI.
449453
* @param {!Object} locals Locals to be injected to the controller.
450454
* @returns {!Object} Created controller instance.
451455
*/
452456
MdCompilerService.prototype._createController = function(options, injectLocals, locals) {
453-
// The third and fourth arguments to $controller are considered private and are undocumented:
454-
// https://github.com/angular/angular.js/blob/master/src/ng/controller.js#L86
455-
// Passing `true` as the third argument causes `$controller` to return a function that
456-
// gets the controller instance instead returning of the instance directly. When the
457-
// controller is defined as a function, `invokeCtrl.instance` is the *same instance* as
458-
// `invokeCtrl()`. However, then the controller is an ES6 class, `invokeCtrl.instance` is a
459-
// *different instance* from `invokeCtrl()`.
460-
var invokeCtrl = this.$controller(options.controller, injectLocals, true, options.controllerAs);
461-
462-
if (getPreAssignBindingsEnabled() && options.bindToController) {
463-
angular.extend(invokeCtrl.instance, locals);
457+
var ctrl;
458+
if ((angular.version.major === 1 && angular.version.minor === 7 && angular.version.dot >= 1) ||
459+
(angular.version.major === 1 && angular.version.minor > 7)) {
460+
ctrl = this.$controller(options.controller, injectLocals);
461+
} else {
462+
// The third argument to $controller is considered private and is undocumented
463+
// in AngularJS prior to 1.7.1:
464+
// https://github.com/angular/angular.js/blob/v1.6.10/src/ng/controller.js#L102-L109
465+
// Passing `true` as the third argument causes `$controller` to return a function that
466+
// gets the controller instance instead of returning the instance directly. When the
467+
// controller is defined as a function, `invokeCtrl.instance` is the *same instance* as
468+
// `invokeCtrl()`. However, when the controller is an ES6 class, `invokeCtrl.instance` is a
469+
// *different instance* from `invokeCtrl()`.
470+
var invokeCtrl = this.$controller(options.controller, injectLocals, true);
471+
472+
if (getPreAssignBindingsEnabled() && options.bindToController) {
473+
angular.extend(invokeCtrl.instance, locals);
474+
}
475+
476+
// Instantiate and initialize the specified controller.
477+
ctrl = invokeCtrl();
464478
}
465479

466-
// Instantiate and initialize the specified controller.
467-
var ctrl = invokeCtrl();
480+
if (options.controllerAs) {
481+
injectLocals.$scope[options.controllerAs] = ctrl;
482+
}
468483

469484
if (!getPreAssignBindingsEnabled() && options.bindToController) {
470485
angular.extend(ctrl, locals);

src/core/services/compiler/compiler.spec.js

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ describe('$mdCompiler service', function() {
112112
var data = compile({
113113
template: '<span>hello</span>'
114114
});
115-
var scope = $rootScope.$new();
115+
var scope = $rootScope.$new(false);
116116
data.link(scope);
117117
expect(data.element.scope()).toBe(scope);
118118
}));
@@ -127,7 +127,7 @@ describe('$mdCompiler service', function() {
127127
this.injectedOne = one;
128128
}
129129
});
130-
var scope = $rootScope.$new();
130+
var scope = $rootScope.$new(false);
131131
data.link(scope);
132132
expect(data.element.controller()).toBeTruthy();
133133
expect(data.element.controller().injectedOne).toBe(1);
@@ -143,7 +143,7 @@ describe('$mdCompiler service', function() {
143143
}
144144
});
145145

146-
var scope = $rootScope.$new();
146+
var scope = $rootScope.$new(false);
147147
data.link(scope);
148148

149149
expect(ctrlElement).toBe(data.element);
@@ -155,7 +155,7 @@ describe('$mdCompiler service', function() {
155155
controller: function Ctrl() {},
156156
controllerAs: 'myControllerAs'
157157
});
158-
var scope = $rootScope.$new();
158+
var scope = $rootScope.$new(false);
159159
data.link(scope);
160160
expect(scope.myControllerAs).toBe(data.element.controller());
161161
}));
@@ -164,12 +164,24 @@ describe('$mdCompiler service', function() {
164164

165165
});
166166

167-
[
167+
var bindingStatesToTest;
168+
if (angular.version.major === 1 && angular.version.minor >= 7) {
169+
bindingStatesToTest = [
170+
{respectPreAssignBindingsEnabled: true}
171+
];
172+
} else if (angular.version.major === 1 && angular.version.minor === 6) {
173+
bindingStatesToTest = [
168174
{respectPreAssignBindingsEnabled: true},
169175
{respectPreAssignBindingsEnabled: false},
170-
// TODO change `equivalentTo` to `true` in Material 1.2.
171176
{respectPreAssignBindingsEnabled: '"default"', equivalentTo: false}
172-
].forEach(function(options) {
177+
];
178+
} else if (angular.version.major === 1 && angular.version.minor < 6) {
179+
bindingStatesToTest = [
180+
{respectPreAssignBindingsEnabled: false}
181+
];
182+
}
183+
184+
bindingStatesToTest.forEach(function(options) {
173185
var realRespectPreAssignBindingsEnabled = options.respectPreAssignBindingsEnabled;
174186
var respectPreAssignBindingsEnabled = angular.isDefined(options.equivalentTo) ?
175187
options.equivalentTo :
@@ -224,8 +236,8 @@ describe('$mdCompiler service', function() {
224236
expect(isInstantiated).toBe(true);
225237
});
226238

227-
// Bindings are not preassigned only if we respect the AngularJS config and they're
228-
// disabled there. This logic will change in Material 1.2.0.
239+
// Bindings are not pre-assigned if we respect the AngularJS config and pre-assigning
240+
// them is disabled there.
229241
if (respectPreAssignBindingsEnabled && !preAssignBindingsEnabledInAngularJS) {
230242
it('disabled should assign bindings after constructor', function() {
231243
var isInstantiated = false;
@@ -400,7 +412,7 @@ describe('$mdCompiler service', function() {
400412

401413
it('should preserve a previous linked scope', function() {
402414

403-
var scope = $rootScope.$new();
415+
var scope = $rootScope.$new(false);
404416

405417
var data = compile({
406418
contentElement: $compile('<div>With Scope</div>')(scope)
@@ -445,7 +457,7 @@ describe('$mdCompiler service', function() {
445457
beforeEach(inject(function($injector) {
446458
$mdCompiler = $injector.get('$mdCompiler');
447459
$rootScope = $injector.get('$rootScope');
448-
pageScope = $rootScope.$new();
460+
pageScope = $rootScope.$new(false);
449461
}));
450462

451463
it('should assign bindings by $onInit for ES6 classes', function(done) {

0 commit comments

Comments
 (0)