Frontmatter
| id | 9413 |
| title | Create Async Subtree Loading for `Neo.data.TreeStore` |
| state | Closed |
| labels | enhancementaicore |
| assignees | tobiu |
| createdAt | Mar 9, 2026, 12:33 PM |
| updatedAt | Mar 9, 2026, 3:31 PM |
| githubUrl | https://github.com/neomjs/neo/issues/9413 |
| author | tobiu |
| commentsCount | 1 |
| parentIssue | 9404 |
| subIssues | [] |
| subIssuesCompleted | 0 |
| subIssuesTotal | 0 |
| blockedBy | [] |
| blocking | [] |
| closedAt | Mar 9, 2026, 3:31 PM |
Create Async Subtree Loading for Neo.data.TreeStore
tobiu added parent issue #9404 on Mar 9, 2026, 12:34 PM
tobiu assigned to @tobiu on Mar 9, 2026, 12:34 PM

tobiu
Mar 9, 2026, 3:30 PM
Input from Gemini 3.1 Pro:
✦ Implemented Async Subtree Loading for
Neo.data.TreeStore.
- Added
isLoading: BooleantoNeo.data.TreeModel.- Upgraded
TreeStore.expand()to handle asynchronous requests viaload({append: true})when expanding unloaded nodes.- Added state tracking (
isLoading = true) andrecordChangeevents to trigger UI spinners.- Hardened
TreeStore.add()to ensure it only mathematically computes the visible flat list for truly new root nodes, gracefully swallowing asynchronously fetched child subtrees soexpand()can splice them into the correct location without duplicating array append operations.Changes pushed to
dev.
tobiu closed this issue on Mar 9, 2026, 3:31 PM
tobiu cross-referenced by #9416 on Mar 9, 2026, 3:46 PM
Goal
Enhance the
Neo.data.TreeStoreto support asynchronous loading of child nodes when a collapsed node is expanded, laying the groundwork for handling massive hierarchical datasets without a fullBufferedStore.Architecture & Mechanics
We will leverage the existing
Store.load()mechanics (specifically theopts.appendpattern) andCollection.splice()to inject new data into the tree without destroying the current view.expanded: true(orcollapsed: false), the payload must contain its direct children. TheTreeStoreparsing logic should throw a warning if this condition is violated to prevent rendering empty folders.totalCount(Data Perspective): Represents the total size of the fully expanded tree on the backend (useful for metadata/pagination, but not for the scrollbar).count(UI Perspective): Managed by theCollection. Represents the length of the flattened_itemsarray (only the visible nodes). This drives theGridBodyscrollbar height andaria-rowcount.expand(nodeId)is called on a node that does not have its children loaded in the#childrenMap:isLoading: true(triggers UI spinner).store.load({ params: { parentId: nodeId }, append: true })).#childrenMap.isLoading: false,expanded: true.spliceto inject the new child nodes into the flatteneditemsarray directly below the parent.mutateevent will automatically update the grid's rendering and scrollbar.Future-Proofing
By relying on
Collection.spliceand the flattened_itemsarray, this implementation provides the exact hooks needed for a futureBufferedStore(which would inject placeholder rows instead of actual data rows, triggering targeted fetches as they scroll into view).Dependencies
TreeStoreimplementation (#9406).