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

Commit f6534d6

Browse files
Splaktarjelbourn
authored andcommitted
fix(compiler): remove dependency on AngularJS private API (#11320)
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
1 parent 9cc165f commit f6534d6

File tree

5 files changed

+108
-75
lines changed

5 files changed

+108
-75
lines changed

Diff for: .travis.yml

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ branches:
2525

2626
jobs:
2727
include:
28+
- env: "NG_VERSION=1.5"
2829
- env: "NG_VERSION=1.6"
2930
- env: "NG_VERSION=1.7"
3031
- env: "NG_VERSION=snapshot"

Diff for: package-lock.json

+24-24
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: package.json

+8-8
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.2",
25+
"angular-animate": "^1.7.2",
26+
"angular-aria": "^1.7.2",
27+
"angular-messages": "^1.7.2",
28+
"angular-mocks": "^1.7.2",
29+
"angular-route": "^1.7.2",
30+
"angular-sanitize": "^1.7.2",
31+
"angular-touch": "^1.7.2",
3232
"angularytics": "^0.4.0",
3333
"canonical-path": "0.0.2",
3434
"cli-color": "^1.0.0",

Diff for: src/core/services/compiler/compiler.js

+55-32
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,9 @@ function MdCompilerProvider($compileProvider) {
102102
* @name $mdCompilerProvider#respectPreAssignBindingsEnabled
103103
*
104104
* @param {boolean=} respected update the `respectPreAssignBindingsEnabled` state if provided,
105-
* otherwise just return the current Material `respectPreAssignBindingsEnabled` state.
106-
* @returns {boolean|MdCompilerProvider} current value if used as getter or itself (chaining)
107-
* if used as setter
105+
* otherwise just return the current Material `respectPreAssignBindingsEnabled` state.
106+
* @returns {boolean|MdCompilerProvider} current value, if used as a getter, or itself (chaining)
107+
* if used as a setter.
108108
*
109109
* @description
110110
* Call this method to enable/disable whether Material-specific (dialog/panel/toast/bottomsheet)
@@ -114,26 +114,36 @@ function MdCompilerProvider($compileProvider) {
114114
*
115115
* If disabled (`false`), the compiler assigns the value of each of the bindings to the
116116
* properties of the controller object before the constructor of this object is called.
117+
* The ability to disable this settings is **deprecated** and will be removed in
118+
* AngularJS Material 1.2.0.
117119
*
118120
* If enabled (`true`) the behavior depends on the AngularJS version used:
119121
*
120-
* - `<1.5.10` - bindings are pre-assigned.
121-
* - `>=1.5.10 <1.7` - behaves like set to whatever `$compileProvider.preAssignBindingsEnabled()` reports.
122-
* If the `preAssignBindingsEnabled` flag wasn't set manually, it defaults to pre-assigning bindings
123-
* with AngularJS `1.5.x` and to calling the constructor first with AngularJS `1.6.x`.
124-
* - `>=1.7` - the compiler calls the constructor first before assigning bindings and
122+
* - `<1.5.10`
123+
* - Bindings are pre-assigned.
124+
* - `>=1.5.10 <1.7`
125+
* - Respects whatever `$compileProvider.preAssignBindingsEnabled()` reports. If the
126+
* `preAssignBindingsEnabled` flag wasn't set manually, it defaults to pre-assigning bindings
127+
* with AngularJS `1.5` and to calling the constructor first with AngularJS `1.6`.
128+
* - `>=1.7`
129+
* - The compiler calls the constructor first before assigning bindings and
125130
* `$compileProvider.preAssignBindingsEnabled()` no longer exists.
126131
*
127-
* The default value is `false` but will change to `true` in AngularJS Material 1.2.
132+
* Defaults
133+
* - The default value is `false` in AngularJS 1.6 and earlier.
134+
* - It is planned to fix this value to `true` and not allow the `false` value in
135+
* AngularJS Material 1.2.0.
128136
*
129-
* It is recommended to set this flag to `true` in AngularJS Material 1.1.x. The only reason
130-
* it's not set that way by default is backwards compatibility. Not setting the flag to `true`
131-
* when AngularJS' `$compileProvider.preAssignBindingsEnabled()` is set to `false`
132-
* (i.e. default behavior in AngularJS 1.6 or newer) makes it hard to unit test
137+
* It is recommended to set this flag to `true` when using AngularJS Material 1.1.x with
138+
* AngularJS versions >= 1.5.10. The only reason it's not set that way by default is backwards
139+
* compatibility.
140+
*
141+
* By not setting the flag to `true` when AngularJS' `$compileProvider.preAssignBindingsEnabled()`
142+
* is set to `false` (i.e. default behavior in AngularJS 1.6 or newer), unit testing of
133143
* Material Dialog/Panel/Toast/BottomSheet controllers using the `$controller` helper
134-
* as it always follows the `$compileProvider.preAssignBindingsEnabled()` value.
144+
* is problematic as it always follows AngularJS' `$compileProvider.preAssignBindingsEnabled()`
145+
* value.
135146
*/
136-
// TODO change it to `true` in Material 1.2.
137147
var respectPreAssignBindingsEnabled = false;
138148
this.respectPreAssignBindingsEnabled = function(respected) {
139149
if (angular.isDefined(respected)) {
@@ -147,11 +157,11 @@ function MdCompilerProvider($compileProvider) {
147157
/**
148158
* @private
149159
* @description
150-
* This function returns `true` if AngularJS Material-specific (dialog/panel/toast/bottomsheet) controllers have
151-
* bindings pre-assigned in controller constructors and `false` otherwise.
160+
* This function returns `true` if AngularJS Material-specific (dialog/panel/toast/bottomsheet)
161+
* controllers have bindings pre-assigned in controller constructors and `false` otherwise.
152162
*
153-
* Note that this doesn't affect directives/components created via regular AngularJS methods which constitute most
154-
* Material and user-created components; their behavior can be checked via
163+
* Note that this doesn't affect directives/components created via regular AngularJS methods
164+
* which constitute most Material and user-created components; their behavior can be checked via
155165
* `$compileProvider.preAssignBindingsEnabled()` in AngularJS `>=1.5.10 <1.7.0`.
156166
*
157167
* @returns {*} current preAssignBindingsEnabled state
@@ -444,30 +454,43 @@ function MdCompilerProvider($compileProvider) {
444454

445455
/**
446456
* Creates and instantiates a new controller with the specified options.
447-
* @param {!Object} options Options that include the controller
457+
* @param {!Object} options Options that include the controller function or string.
448458
* @param {!Object} injectLocals Locals to to be provided in the controller DI.
449459
* @param {!Object} locals Locals to be injected to the controller.
450460
* @returns {!Object} Created controller instance.
451461
*/
452462
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
463+
var ctrl;
464+
var preAssignBindingsEnabled = getPreAssignBindingsEnabled();
465+
// The third argument to $controller is considered private and undocumented:
466+
// https://github.com/angular/angular.js/blob/v1.6.10/src/ng/controller.js#L102-L109.
467+
// TODO remove the use of this third argument in AngularJS Material 1.2.0.
455468
// 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
469+
// gets the controller instance instead of returning the instance directly. When the
457470
// 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
471+
// `invokeCtrl()`. However, when the controller is an ES6 class, `invokeCtrl.instance` is a
459472
// *different instance* from `invokeCtrl()`.
460-
var invokeCtrl = this.$controller(options.controller, injectLocals, true, options.controllerAs);
473+
if (preAssignBindingsEnabled) {
474+
var invokeCtrl = this.$controller(options.controller, injectLocals, true);
461475

462-
if (getPreAssignBindingsEnabled() && options.bindToController) {
463-
angular.extend(invokeCtrl.instance, locals);
464-
}
476+
if (options.bindToController) {
477+
angular.extend(invokeCtrl.instance, locals);
478+
}
465479

466-
// Instantiate and initialize the specified controller.
467-
var ctrl = invokeCtrl();
480+
// Use the private API callback to instantiate and initialize the specified controller.
481+
ctrl = invokeCtrl();
482+
} else {
483+
// If we don't need to pre-assign bindings, avoid using the private API third argument and
484+
// related callback.
485+
ctrl = this.$controller(options.controller, injectLocals);
486+
487+
if (options.bindToController) {
488+
angular.extend(ctrl, locals);
489+
}
490+
}
468491

469-
if (!getPreAssignBindingsEnabled() && options.bindToController) {
470-
angular.extend(ctrl, locals);
492+
if (options.controllerAs) {
493+
injectLocals.$scope[options.controllerAs] = ctrl;
471494
}
472495

473496
// Call the $onInit hook if it's present on the controller.

Diff for: src/core/services/compiler/compiler.spec.js

+20-11
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,21 @@ describe('$mdCompiler service', function() {
164164

165165
});
166166

167-
[
167+
var bindingStatesToTest;
168+
if (angular.version.major === 1 && angular.version.minor >= 6) {
169+
bindingStatesToTest = [
168170
{respectPreAssignBindingsEnabled: true},
169171
{respectPreAssignBindingsEnabled: false},
170-
// TODO change `equivalentTo` to `true` in Material 1.2.
172+
// TODO change `equivalentTo` to `true` in Material 1.2.0.
171173
{respectPreAssignBindingsEnabled: '"default"', equivalentTo: false}
172-
].forEach(function(options) {
174+
];
175+
} else if (angular.version.major === 1 && angular.version.minor < 6) {
176+
bindingStatesToTest = [
177+
{respectPreAssignBindingsEnabled: false}
178+
];
179+
}
180+
181+
bindingStatesToTest.forEach(function(options) {
173182
var realRespectPreAssignBindingsEnabled = options.respectPreAssignBindingsEnabled;
174183
var respectPreAssignBindingsEnabled = angular.isDefined(options.equivalentTo) ?
175184
options.equivalentTo :
@@ -224,8 +233,8 @@ describe('$mdCompiler service', function() {
224233
expect(isInstantiated).toBe(true);
225234
});
226235

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.
236+
// Bindings are not pre-assigned if we respect the AngularJS config and pre-assigning
237+
// them is disabled there. This logic will change in AngularJS Material 1.2.0.
229238
if (respectPreAssignBindingsEnabled && !preAssignBindingsEnabledInAngularJS) {
230239
it('disabled should assign bindings after constructor', function() {
231240
var isInstantiated = false;
@@ -400,7 +409,7 @@ describe('$mdCompiler service', function() {
400409

401410
it('should preserve a previous linked scope', function() {
402411

403-
var scope = $rootScope.$new();
412+
var scope = $rootScope.$new(false);
404413

405414
var data = compile({
406415
contentElement: $compile('<div>With Scope</div>')(scope)
@@ -445,7 +454,7 @@ describe('$mdCompiler service', function() {
445454
beforeEach(inject(function($injector) {
446455
$mdCompiler = $injector.get('$mdCompiler');
447456
$rootScope = $injector.get('$rootScope');
448-
pageScope = $rootScope.$new();
457+
pageScope = $rootScope.$new(false);
449458
}));
450459

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

0 commit comments

Comments
 (0)