From 4d698430b38efa49c97b841238b331340af5fef0 Mon Sep 17 00:00:00 2001 From: Justin Fagnani Date: Wed, 1 Feb 2023 16:00:04 -0800 Subject: [PATCH] Don't throw if ChildPart.parentNode is null (#3615) --- .changeset/early-snakes-complain.md | 5 +++++ packages/lit-html/src/lit-html.ts | 2 +- packages/lit-html/src/test/lit-html_test.ts | 21 +++++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 .changeset/early-snakes-complain.md diff --git a/.changeset/early-snakes-complain.md b/.changeset/early-snakes-complain.md new file mode 100644 index 0000000000..081bccfcba --- /dev/null +++ b/.changeset/early-snakes-complain.md @@ -0,0 +1,5 @@ +--- +'lit-html': patch +--- + +Don't throw in `ChildPart.parentNode` if the `parentNode` is null diff --git a/packages/lit-html/src/lit-html.ts b/packages/lit-html/src/lit-html.ts index 0157d36edc..62be163758 100644 --- a/packages/lit-html/src/lit-html.ts +++ b/packages/lit-html/src/lit-html.ts @@ -1318,7 +1318,7 @@ class ChildPart implements Disconnectable { const parent = this._$parent; if ( parent !== undefined && - parentNode.nodeType === 11 /* Node.DOCUMENT_FRAGMENT */ + parentNode?.nodeType === 11 /* Node.DOCUMENT_FRAGMENT */ ) { // If the parentNode is a DocumentFragment, it may be because the DOM is // still in the cloned fragment during initial render; if so, get the real diff --git a/packages/lit-html/src/test/lit-html_test.ts b/packages/lit-html/src/test/lit-html_test.ts index 9260123c9c..534f28becc 100644 --- a/packages/lit-html/src/test/lit-html_test.ts +++ b/packages/lit-html/src/test/lit-html_test.ts @@ -1715,7 +1715,12 @@ suite('lit-html', () => { }); suite('ChildPart invariants for parentNode, startNode, endNode', () => { + // Let's us get a reference to a directive instance + let currentDirective: CheckNodePropertiesBehavior; + class CheckNodePropertiesBehavior extends Directive { + part?: ChildPart; + render(_parentId?: string, _done?: (err?: unknown) => void) { return nothing; } @@ -1724,6 +1729,9 @@ suite('lit-html', () => { part: ChildPart, [parentId, done]: DirectiveParameters ) { + this.part = part; + // eslint-disable-next-line + currentDirective = this; try { const {parentNode, startNode, endNode} = part; @@ -1822,6 +1830,19 @@ suite('lit-html', () => { await asyncCheckDivRendered; }); + test(`when the parentNode is null`, async () => { + const template = () => html`${checkPart('container')}`; + + // Render the template to instantiate the directive + render(template(), container); + + // Manually clear the container to detach the directive + container.innerHTML = ''; + + // Check that we can access parentNode + assert.equal(currentDirective.part!.parentNode, undefined); + }); + test(`part's parentNode is correct when rendered into a document fragment`, async () => { const fragment = document.createDocumentFragment(); (fragment as unknown as {id: string}).id = 'fragment';