Frontmatter
| id | 9447 |
| title | TreeGrid: Fix 7-click expand/collapse bug and redundant change events |
| state | Closed |
| labels | bugaitesting |
| assignees | tobiu |
| createdAt | Mar 12, 2026, 11:35 AM |
| updatedAt | Mar 12, 2026, 11:37 AM |
| githubUrl | https://github.com/neomjs/neo/issues/9447 |
| author | tobiu |
| commentsCount | 1 |
| parentIssue | 9404 |
| subIssues | [] |
| subIssuesCompleted | 0 |
| subIssuesTotal | 0 |
| blockedBy | [] |
| blocking | [] |
| closedAt | Mar 12, 2026, 11:37 AM |
TreeGrid: Fix 7-click expand/collapse bug and redundant change events
tobiu assigned to @tobiu on Mar 12, 2026, 11:36 AM
tobiu added parent issue #9404 on Mar 12, 2026, 11:37 AM

tobiu
Mar 12, 2026, 11:37 AM
Fixed by removing redundant manual onRecordChange calls in TreeStore.mjs and batching multiple property assignments with node.set({...}) to fire a single clean mutate event. E2E test added to verify toggle behavior.
tobiu closed this issue on Mar 12, 2026, 11:37 AM
Problem
Users reported a bug in the TreeGrid where clicking an expand/collapse icon required 7 clicks before the icon visually updated to reflect the new state, even though rows were added/removed correctly on the first click.
Analysis
The
TreeStore.mjsexpandandcollapsemethods were manually firingme.onRecordChangeimmediately after mutating a node property (e.g.,node.collapsed = false). However, sincenodeis guaranteed to be a fully hydratedRecordinstance (viame.get()), the property mutation itself already triggers thenotifyChangesetter inRecordFactory, which incrementsrecord.versionand firesonRecordChangenatively.The duplicate, manual
onRecordChangecall fired a second event without incrementing therecord.version. This caused a race condition ingrid.BodyandComponent.mjs#cellRenderer, where the VDOM update short-circuited becausecomponent.lastRecordVersion === record.version. The 7 clicks forced a row recycle, bypassing the short-circuit and finally updating the DOM.Solution
me.onRecordChangecalls incollapse()andexpand().node.collapsed = true), relying on theRecordFactorysetter.node.set({ isLoading: false, collapsed: false })) to fire a single, cleanmutateevent.GridTree.spec.mjs) to verify the correct node expand/collapse behavior on the first click.