Replace map with repeat directive for rows rendering#43
Merged
Conversation
This allows table updates without resetting any elements in the context of the row, like a kabob menu.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This allows table updates without resetting any elements in the context of the row, like a kabob menu.
Summary
When
rowsdata updates (e.g. from a polling interval), Lit's.map()destroys and recreates all rowDOM nodes on every render cycle. Any stateful child element inside a row, such as an open
trailhand-action-menuloses its state because the element is replaced with a new instance.Replacing
.map()with Lit'srepeat()directive keys each row torow[this.keyField](defaults to'id'). Lit reuses existing DOM nodes for rows whose key hasn't changed, only creating/destroying nodesfor rows that are genuinely added or removed. Stateful child elements survive data refreshes.
Type of Change
Changes Made
Primary Changes
.map()withrepeat()directive in the row rendering section ofDataTable.render()import { repeat } from 'lit/directives/repeat.js'Secondary/Collateral Changes
Technical Notes
Components:
src/components/data-table/data-table.tsrow rendering changed from.map()torepeat(this._paginatedRows, (row) => row[this.keyField], (row) => html\...`)`Implementation Details
Lit's
.map()treats every re-render as a full replacement with no concept of row identity.repeat()accepts a key function as its second argument and uses it to match old nodes to new data. When the key
is stable (same row ID), the existing
<tr>and all its children are updated in place rather thanrecreated.
The key function uses
row[this.keyField], the existing publickeyFieldproperty (default:'id',configurable via the
key-fieldattribute). No new API surface introduced.lit/directives/repeat.jsis part of thelitpackage already present as a dependency, no newpackages added.
Testing
How to Test
trailhand-tablewith arenderActionsprop that returns atrailhand-action-menurowsprop with the same rows (simulating a poll)Test Coverage
Browsers Tested
Potential Regressions
pagination active
key-fieldattribute should verify their key values are unique per rowChecklist
Additional Context
This fix was identified while integrating
trailhand-tableinto a polling-driven application list view.The table receives fresh
rowsdata every 30 seconds. Withoutrepeat(), every poll cycle caused allopen action menus to close because their DOM nodes were destroyed. The
repeat()directive resolvesthis by preserving node identity across renders.