diff --git a/lib/legacy/legacy-element-mixin.js b/lib/legacy/legacy-element-mixin.js index 7c6c04d6a9..d84a5eb4a2 100644 --- a/lib/legacy/legacy-element-mixin.js +++ b/lib/legacy/legacy-element-mixin.js @@ -101,6 +101,8 @@ export const LegacyElementMixin = dedupingMixin((base) => { // NOTE: Inlined for perf from version of DisableUpgradeMixin. /** @type {boolean|undefined} */ this.__isUpgradeDisabled; + /** @type {boolean|undefined} */ + this.__needsAttributesAtConnected; } /** @@ -196,6 +198,9 @@ export const LegacyElementMixin = dedupingMixin((base) => { * @override */ connectedCallback() { + if (this.__needsAttributesAtConnected) { + this._takeAttributes(); + } // NOTE: Inlined for perf from version of DisableUpgradeMixin. if (!this.__isUpgradeDisabled) { super.connectedCallback(); @@ -301,11 +306,12 @@ export const LegacyElementMixin = dedupingMixin((base) => { this.root = /** @type {HTMLElement} */(this); this.created(); // Pull all attribute values 1x if `legacyNoObservedAttributes` is set. - if (legacyNoObservedAttributes && this.hasAttributes()) { - const a = this.attributes; - for (let i=0, l=a.length; i < l; i++) { - const attr = a[i]; - this.__attributeReaction(attr.name, null, attr.value); + if (legacyNoObservedAttributes) { + if (this.hasAttributes()) { + this._takeAttributes(); + // Element created from scratch or parser generated + } else if (!this.parentNode) { + this.__needsAttributesAtConnected = true; } } // Ensure listeners are applied immediately so that they are @@ -316,6 +322,14 @@ export const LegacyElementMixin = dedupingMixin((base) => { } } + _takeAttributes() { + const a = this.attributes; + for (let i=0, l=a.length; i < l; i++) { + const attr = a[i]; + this.__attributeReaction(attr.name, null, attr.value); + } + } + /** * Called automatically when an element is initializing. * Users may override this method to perform class registration time diff --git a/test/unit/legacy-noattributes.html b/test/unit/legacy-noattributes.html index 91b45662f3..66799153a0 100644 --- a/test/unit/legacy-noattributes.html +++ b/test/unit/legacy-noattributes.html @@ -108,6 +108,27 @@ assert.equal(el.camelCase, 'camelCase'); }); + test('imperative creation', () => { + el = document.createElement('x-attrs'); + // Create attributes in an unpatched way. + const a = document.createAttribute('foo'); + a.value = 'foo'; + el.setAttributeNode(a); + const b = document.createAttribute('bar'); + b.value = 'bar'; + el.setAttributeNode(b); + const c = document.createAttribute('camel-case'); + c.value = 'camelCase'; + el.setAttributeNode(c); + document.body.appendChild(el); + assert.equal(el.foo, 'foo'); + assert.equal(el.$.child1.getAttribute('foo'), 'x-attrs.foo'); + assert.equal(el.$.child1.foo, "x-attrs.foo"); + assert.equal(el.$.child1.$.content.textContent, 'x-attrs.foo'); + assert.equal(el.camelCase, 'camelCase'); + document.body.removeChild(el); + }); + test('created called before attributeChanged', () => { assert.isTrue(el.wasCreatedInAttributeChanged); });