diff --git a/packages/elements/src/create-custom-element.ts b/packages/elements/src/create-custom-element.ts index 79763b63de..93d5dabc2b 100644 --- a/packages/elements/src/create-custom-element.ts +++ b/packages/elements/src/create-custom-element.ts @@ -187,9 +187,15 @@ export function createCustomElement
( inputs.map(({propName}) => propName).forEach(property => { Object.defineProperty(NgElementImpl.prototype, property, { 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, diff --git a/packages/elements/test/create-custom-element_spec.ts b/packages/elements/test/create-custom-element_spec.ts index 450e1eed53..913a5aa1ff 100644 --- a/packages/elements/test/create-custom-element_spec.ts +++ b/packages/elements/test/create-custom-element_spec.ts @@ -94,6 +94,22 @@ if (browserDetection.supportsCustomElements) { expect(strategy.inputs.get('fooFoo')).toBe('foo-foo-value'); expect(strategy.inputs.get('barBar')).toBe('barBar-value'); }); + + it('should properly handle getting/setting properties on the element even if the constructor is not called', + () => { + // Create a custom element while ensuring that the `NgElementStrategy` is not created + // inside the constructor. This is done to emulate the behavior of some polyfills that do + // not call the constructor. + strategyFactory.create = () => undefined as unknown as NgElementStrategy; + const element = new NgElementCtor(injector); + strategyFactory.create = TestStrategyFactory.prototype.create; + + element.fooFoo = 'foo-foo-value'; + element.barBar = 'barBar-value'; + + expect(strategy.inputs.get('fooFoo')).toBe('foo-foo-value'); + expect(strategy.inputs.get('barBar')).toBe('barBar-value'); + }); }); }