From 97df916e8ea04256d2a702639cc0727b3cca93e5 Mon Sep 17 00:00:00 2001 From: Andrew Seier Date: Tue, 23 May 2023 22:53:04 -0700 Subject: [PATCH] Ensure computation on initialization. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This handles a nuanced edge case where internal, computed properties can be incorrect if they were interrogated between host construction and initialization. For example: ```javascript // This will trigger construction (assuming the element is defined). const element = document.createElement('my-element'); // Do things after construction, before initialization. // This will trigger initialization (again, assuming definition). document.body.append(element); // Do things after initialization while connected. ``` This change set should guarantee that after initialization, during connection — things will be correct. We cannot make such guarantees when not connected due to lack of eventing around attribute callbacks. Closes #143. --- test/test-computed-properties.js | 13 +++++++++++++ x-element.js | 5 ++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/test/test-computed-properties.js b/test/test-computed-properties.js index a4453bf..869590d 100644 --- a/test/test-computed-properties.js +++ b/test/test-computed-properties.js @@ -213,6 +213,19 @@ it('does correct NaN checking', () => { assert(el.count === count); }); +it('resets compute validity on initialization to catch upgrade edge cases with internal, computed properties', () => { + const el = document.createElement('test-element'); + el.setAttribute('a', '1'); + el.setAttribute('b', '2'); + assert(el.a === undefined); + assert(el.b === undefined); + assert(Number.isNaN(el.internal.c)); + document.body.append(el); + assert(el.a === 1); + assert(el.b === 2); + assert(el.internal.c === 3); +}); + it('cannot be written to from host', () => { const el = document.createElement('test-element'); document.body.append(el); diff --git a/x-element.js b/x-element.js index 1af8cad..441ee4b 100644 --- a/x-element.js +++ b/x-element.js @@ -646,7 +646,7 @@ export default class XElement extends HTMLElement { static #initializeHost(host) { const hostInfo = XElement.#hosts.get(host); - const { initialized, invalidProperties } = hostInfo; + const { computeMap, initialized, invalidProperties } = hostInfo; if (initialized === false) { XElement.#upgradeOwnProperties(host); // Only reflect attributes when the element is connected. @@ -661,6 +661,9 @@ export default class XElement extends HTMLElement { XElement.#setPropertyValue(host, property, property.default(host, property.initial())); } invalidProperties.add(property); + if (property.compute) { + computeMap.get(property).valid = false; + } } hostInfo.initialized = true; return true;