Skip to content

for:each within for:each without explicit key can lead to vdom errors #4889

Open
@nolanlawson

Description

@nolanlawson

(Salesforce Known Issue)

If you have an iteration (for:each) within another iteration:

<template>
    <template for:each={children} for:item="child">
        <x-row lwc:if={child.renderMe} prop={child} key={child.id}></x-row>
        <template lwc:if={child.children} for:each={child.children} for:item="grandchild">
            <x-row lwc:if={grandchild.renderMe} prop={grandchild} key={grandchild.id}></x-row>
        </template>
    </template>
</template>

... and if you have a sufficient number of lwc:if layers and duplicated keys between the grandchildren and the children, then you can get a runtime error:

TypeError: Cannot use 'in' operator to search for 'prop' in undefined

Thrown by:

Or:

TypeError: Failed to execute 'removeChild' on 'Node': parameter 1 is not of type 'Node'.

Thrown by:

const removedNode = removeChild.call(this, oldChild);

One workaround is to put a key around the inner loop:

 <template>
     <template for:each={children} for:item="child">
         <x-row lwc:if={child.renderMe} prop={child} key={child.id}></x-row>
+        <div key={child.id}>
         <template lwc:if={child.children} for:each={child.children} for:item="grandchild">
             <x-row lwc:if={grandchild.renderMe} prop={grandchild} key={grandchild.id}></x-row>
         </template>
+        </div>
     </template>
 </template>

Another workaround is to flatten the array. E.g.:

get flattenedArray() {
  return this.children.map(child => [child, ...child.children]).flat() // something like this
}

... and then use a single for:each:

<template for:each={flattenedArray} for:item="child">
    <!-- ... --->
</template>

Repro for first error: nolanlawson/lwc-barebone@836362a
Repro for second error: nolanlawson/lwc-barebone@a97223c

Repro steps: pnpm i && pnpm run dev

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions