Skip to content

Path incorrectly calculated when moving nodes to different parent levels #28

@hanneshoepfnerio

Description

@hanneshoepfnerio

Version: v4.5.0-rc01

 Description:                                                                                                                        
                                                                                                                                     
 When moving a node from one parent to a different parent level, the library incorrectly calculates the new path, resulting in       
 malformed paths that cause subsequent operations to fail with "Source node not found" errors.                                       
                                                                                                                                     
 Steps to Reproduce:                                                                                                                 
                                                                                                                                     
 1. Create a tree with nested nodes using LTree path notation                                                                        
 2. Configure tree with idMember="path", pathMember="path", and orderMember="sortOrder"                                              
 3. Move a node from a nested parent (e.g., 1.1.3 under parent 1.1) to root level (parent 1)                                         
 4. Observe the path becomes 1.1.1.3 instead of expected 1.5 or similar                                                              
                                                                                                                                     
 Example Data:                                                                                                                       
                                                                                                                                     
 let data = [                                                                                                                        
   { id: '1', path: '1', title: 'Root Folder', type: 'folder', sortOrder: 10 },                                                      
   { id: '1.1', path: '1.1', title: 'My Folder', type: 'folder', sortOrder: 10, isDraggable: true },                                 
   { id: '1.1.1', path: '1.1.1', title: 'Playlist 1', type: 'playlist', sortOrder: 10, isDraggable: true },                          
   { id: '1.1.2', path: '1.1.2', title: 'Playlist 2', type: 'playlist', sortOrder: 20, isDraggable: true },                          
   { id: '1.1.3', path: '1.1.3', title: 'My Folder1', type: 'folder', sortOrder: 30, isDraggable: true },                            
   { id: '1.2', path: '1.2', title: 'Playlist 3', type: 'playlist', sortOrder: 30, isDraggable: true }                               
 ];                                                                                                                                  
                                                                                                                                     
 Tree Configuration:                                                                                                                 
                                                                                                                                     
 <Tree                                                                                                                               
   {data}                                                                                                                            
   treeId="tree-component-example"                                                                                                   
   idMember="path"                                                                                                                   
   pathMember="path"                                                                                                                 
   displayValueMember="title"                                                                                                        
   orderMember="sortOrder"                                                                                                           
   shouldDisplayDebugInformation={true}                                                                                              
   beforeDropCallback={beforeDrop}                                                                                                   
   onNodeDrop={handleDrop}                                                                                                           
 />                                                                                                                                  
                                                                                                                                     
 Console Output:                                                                                                                     
                                                                                                                                     
 // Initial drag - path is correct                                                                                                   
 [Tree] _onNodeDragStart - node: 1.1.3                                                                                               
                                                                                                                                     
 // First move within same parent - works correctly                                                                                  
 refreshSiblings: Re-sorted 3 children under "1.1":                                                                                  
   0: {path: '1.1.1', sortOrder: 10}                                                                                                 
   1: {path: '1.1.3', sortOrder: 15}                                                                                                 
   2: {path: '1.1.2', sortOrder: 20}                                                                                                 
 [Tree] Auto-moved node: {success: true}                                                                                             
                                                                                                                                     
 // Second move to different parent - path becomes WRONG                                                                             
 [Tree] _onNodeDragStart - node: 1.1.3                                                                                               
 refreshSiblings: Re-sorted 5 children under "1":                                                                                    
   0: {path: '1.1.1.3', sortOrder: 0}  ← INCORRECT PATH!                                                                             
   1: {path: '1.1', sortOrder: 10}                                                                                                   
   2: {path: '1.2', sortOrder: 30}                                                                                                   
   3: {path: '1.3', sortOrder: 40}                                                                                                   
   4: {path: '1.4', sortOrder: 50}                                                                                                   
 [Tree] Auto-moved node: {success: true}                                                                                             
                                                                                                                                     
 // Third move attempt - fails because tree has wrong path                                                                           
 [Tree] _onNodeDragStart - node: 1.1.1.3  ← Now using WRONG path                                                                     
 [Tree] Auto-moved node: {success: false, error: 'Source node not found: 1.1.1.3'}                                                   
                                                                                                                                     
 Expected Behavior:                                                                                                                  
                                                                                                                                     
 When moving node 1.1.3 from parent 1.1 to parent 1 (above node 1.3), the new path should be calculated as 1.5 or similar valid      
 root-level path, not 1.1.1.3.                                                                                                       
                                                                                                                                     
 Actual Behavior:                                                                                                                    
                                                                                                                                     
 The path becomes 1.1.1.3 - an invalid path that appears to concatenate parts of the old path incorrectly. Subsequent drag           
 operations fail with "Source node not found" errors because the tree's internal state has the wrong path.                           
                                                                                                                                     
 Workaround:                                                                                                                         
                                                                                                                                     
 Currently blocking cross-parent moves in beforeDropCallback to prevent the bug:                                                     
                                                                                                                                     
 function beforeDrop(dropNode, draggedNode, position) {                                                                              
   const draggedParent = draggedNode.parentPath;                                                                                     
   const dropParent = position === 'child' ? dropNode.path : dropNode.parentPath;                                                    
                                                                                                                                     
   if (draggedParent !== dropParent) {                                                                                               
     console.warn('Cross-parent move blocked - library bug');                                                                        
     return false;                                                                                                                   
   }                                                                                                                                 
                                                                                                                                     
   return true;                                                                                                                      
 }                                                                                                                                   
                                                                                                                                     
 Environment:                                                                                                                        
                                                                                                                                     
 - Browser: Chrome/Firefox                                                                                                           
 - SvelteKit Version: 5                                                                                                              
 - @keenmate/svelte-treeview: v4.5.0-rc01                                                                                            
 - Node: (your version)                                                                                                              
                                                                                                                                     
 Additional Notes:                                                                                                                   
                                                                                                                                     
 - Moving nodes WITHIN the same parent works correctly                                                                               
 - Dropping nodes INTO folders (position='child') may have the same issue                                                            
 - The bug appears to be in the path recalculation logic in ltree.svelte.js or the refreshSiblings function                          
 - Setting unique sortOrder values for siblings does not fix the issue                                                               
                                                                                                                                     
 ---                                                                                                                                 
 Copy-Paste Ready Version for GitHub:                                                                                                
                                                                                                                                     
 ### Bug: Path incorrectly calculated when moving nodes between hierarchy levels                                                     
                                                                                                                                     
 **Version:** v4.5.0-rc01                                                                                                            
                                                                                                                                     
 When moving a node from one parent to a different parent level, the library incorrectly calculates the new path, causing "Source    
  node not found" errors.                                                                                                            
                                                                                                                                     
 **Reproduce:**                                                                                                                      
 1. Move node `1.1.3` (child of `1.1`) to root level (sibling of `1.1`)                                                              
 2. Path becomes `1.1.1.3` instead of expected root-level path like `1.5`                                                            
 3. Subsequent operations fail with "Source node not found: 1.1.1.3"                                                                 
                                                                                                                                     
 **Console output:**                                                                                                                 
 refreshSiblings: Re-sorted 5 children under "1":                                                                                    
   0: {path: '1.1.1.3', sortOrder: 0}  ← WRONG!                                                                                      
                                                                                                                                     
 **Config:**                                                                                                                         
 ```svelte                                                                                                                           
 <Tree                                                                                                                               
   {data}                                                                                                                            
   idMember="path"                                                                                                                   
   pathMember="path"                                                                                                                 
   orderMember="sortOrder"                                                                                                           
   beforeDropCallback={beforeDrop}                                                                                                   
   onNodeDrop={handleDrop}                                                                                                           
 />                                                                                                                                  
                                                                                                                                     
 Expected: Path should be 1.5 or similar valid root path                                                                             
 Actual: Path becomes 1.1.1.3 (malformed)                                                                                            
                                                                                                                                     
 Workaround: Block cross-parent moves in beforeDropCallback                                                                          
                                                                                                                                     
 Moving within same parent works correctly.   

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions