fix(elements): do not break when the constructor of an Angular Element is not called (#36114)

Previously, the correct behavior of Angular custom elements relied on
the constructor being called (and thus the `injector` property being
initialized). However, some polyfills (e.g. `document-register-element`)
do not call the constructor of custom elements, which resulted in the
`injector` property being undefined and the `NgElementStrategy` failing
to be instantiated.

This commit fixes it by being tolerant to the `injector` property being
undefined and falling back to the injector passed to the
`createCustomElement()` config.

NOTE:
We don't have proper tests exercising the situation where the
constructor is not called. For now this is tested using a Google
internal test suite (which is how this issue was caught).
This commit also adds a rudimentary unit test to emulate this situation.

PR Close #36114
This commit is contained in:
George Kalpakas
2020-05-20 11:10:27 +03:00
committed by Kara Erickson
parent 2fc5ae561b
commit 89b44d1900
2 changed files with 33 additions and 7 deletions

View File

@ -144,8 +144,9 @@ export function createCustomElement<P>(
//
// TODO(andrewseguin): Add e2e tests that cover cases where the constructor isn't called. For
// now this is tested using a Google internal test suite.
if (this._ngElementStrategy === null) {
const strategy = this._ngElementStrategy = strategyFactory.create(this.injector);
if (!this._ngElementStrategy) {
const strategy = this._ngElementStrategy =
strategyFactory.create(this.injector || config.injector);
// Collect pre-existing values on the element to re-apply through the strategy.
const preExistingValues =
@ -173,12 +174,10 @@ export function createCustomElement<P>(
return this._ngElementStrategy!;
}
private readonly injector: Injector;
private _ngElementStrategy: NgElementStrategy|null = null;
private _ngElementStrategy?: NgElementStrategy;
constructor(injector?: Injector) {
constructor(private readonly injector?: Injector) {
super();
this.injector = injector || config.injector;
}
attributeChangedCallback(