Revert "refactor(elements): simplify accessing NgElementStrategy (#36114)"

This reverts commit fa073bafbd
because it is causing the side effects test to break on the
9.1.x branch.
This commit is contained in:
Kara Erickson
2020-05-20 11:07:17 -07:00
parent 2c4cfa6f2c
commit 4e2500278c

View File

@ -136,35 +136,31 @@ export function createCustomElement<P>(
// field externs. So using quoted access to explicitly prevent renaming.
static readonly['observedAttributes'] = Object.keys(attributeToPropertyInputs);
protected get ngElementStrategy(): NgElementStrategy {
// NOTE:
// Some polyfills (e.g. `document-register-element`) do not call the constructor, therefore
// it is not safe to set `ngElementStrategy` in the constructor and assume it will be
// available inside the methods.
//
// 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) {
this._ngElementStrategy = strategyFactory.create(this.injector);
}
return this._ngElementStrategy;
}
private readonly injector: Injector;
private _ngElementStrategy: NgElementStrategy|null = null;
constructor(injector?: Injector) {
super();
this.injector = injector || config.injector;
// Note that some polyfills (e.g. document-register-element) do not call the constructor.
// Do not assume this strategy has been created.
// 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.
this.ngElementStrategy = strategyFactory.create(injector || config.injector);
}
attributeChangedCallback(
attrName: string, oldValue: string|null, newValue: string, namespace?: string): void {
if (!this.ngElementStrategy) {
this.ngElementStrategy = strategyFactory.create(config.injector);
}
const propName = attributeToPropertyInputs[attrName]!;
this.ngElementStrategy.setInputValue(propName, newValue);
}
connectedCallback(): void {
if (!this.ngElementStrategy) {
this.ngElementStrategy = strategyFactory.create(config.injector);
}
this.ngElementStrategy.connect(this);
// Listen for events from the strategy and dispatch them as custom events
@ -175,9 +171,8 @@ export function createCustomElement<P>(
}
disconnectedCallback(): void {
// Not using `this.ngElementStrategy` to avoid unnecessarily creating the `NgElementStrategy`.
if (this._ngElementStrategy) {
this._ngElementStrategy.disconnect();
if (this.ngElementStrategy) {
this.ngElementStrategy.disconnect();
}
if (this.ngElementEventsSubscription) {
@ -187,18 +182,22 @@ export function createCustomElement<P>(
}
}
// TypeScript 3.9+ defines getters/setters as configurable but non-enumerable properties (in
// compliance with the spec). This breaks emulated inheritance in ES5 on environments that do not
// natively support `Object.setPrototypeOf()` (such as IE 9-10).
// Update the property descriptor of `NgElementImpl#ngElementStrategy` to make it enumerable.
Object.defineProperty(NgElementImpl.prototype, 'ngElementStrategy', {enumerable: true});
// Add getters and setters to the prototype for each property input. If the config does not
// contain property inputs, use all inputs by default.
inputs.map(({propName}) => propName).forEach(property => {
Object.defineProperty(NgElementImpl.prototype, property, {
get: function() { return this.ngElementStrategy.getInputValue(property); },
set: function(newValue: any) { this.ngElementStrategy.setInputValue(property, newValue); },
get: function() {
if (!this.ngElementStrategy) {
this.ngElementStrategy = strategyFactory.create(config.injector);
}
return this.ngElementStrategy.getInputValue(property);
},
set: function(newValue: any) {
if (!this.ngElementStrategy) {
this.ngElementStrategy = strategyFactory.create(config.injector);
}
this.ngElementStrategy.setInputValue(property, newValue);
},
configurable: true,
enumerable: true,
});