I'm new to angular material drag and drop.
My app is using an n-ary tree, and since I don't know its form apriori, I've been forced to use a recursive template in order to represent it.
The last couple of days I've been trying to use Angular material drag and drop to reorder siblings. If I remove the root node everything works just fine, but I cannot remove the root node since I need it to traverse the tree for other operations.
Bellow is a simplified form of the tree. In reality, the tree can have many more branches and leaves, but I wanted to keep it simple.
Json of the n-ary tree (root node with the 3 children nodes I want to be able to drag and drop):
[
{
"orderIndex": 0,
"id": "5a4f87ce-c52d-4cc1-b587-21898ded5cc0",
"parentId": "5a4f87ce-c52d-4cc1-b587-21898ded5cc0",
"name": "Interface1",
"conditions": "None",
"text": null,
"description": "description",
"children": [
{
"orderIndex": 0,
"id": "5a4f87ce-c527-4cc1-b587-22898ded5cc0",
"parentId": "5a4f87ce-c52d-4cc1-b587-21898ded5cc0",
"name": "Interface2",
"conditions": "None",
"text": null,
"description": "description",
"children": [],
"errors": null
},
{
"orderIndex": 1,
"id": "5a4f87ce-c527-4cc8-b587-26898ded5cc0",
"parentId": "5a4f87ce-c527-4cc8-b587-23898ded5cc0",
"name": "Interface6",
"conditions": "None",
"text": null,
"description": "description",
"children": [],
"errors": null
},
{
"orderIndex": 2,
"id": "5a4f87ce-c525-4cc1-b587-25898ded5cc0",
"parentId": "5a4f87ce-c52e-4cc1-b587-24898ded5cc0",
"name": "Interface4",
"conditions": "None",
"text": null,
"description": "description",
"children": [],
"errors": null
}
],
"errors": null
}
]
Component:
import { DataService } from './../data.service';
import { Node } from '../_Models/Node';
import {CdkDragDrop, moveItemInArray} from '@angular/cdk/drag-drop';
@Component({
selector: 'app-vnf-main',
templateUrl: './vnf-main.component.html',
styleUrls: ['./vnf-main.component.css']
})
export class VnfMainComponent implements OnInit {
tree: Node[];
constructor(private dataService: DataService) {
}
ngOnInit() {
this.dataService.tree$.subscribe(result => {
this.tree = result;
});
drop(event: CdkDragDrop<Node[]>) {
moveItemInArray(this.tree, event.previousIndex, event.currentIndex);
}
}
Template code:
<table>
<ng-template #recursiveList let-tree>
<div cdkDropList (cdkDropListDropped)="drop($event)">
<div *ngFor="let node of tree; let i=index " cdkDrag>
<tr>
<app-default-node [node]="node"></app-default-node>
<td *ngIf="node.children!==null && node.children.length > 0" cdkDrag>
<ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: node.children }"></ng-container>
</td>
</tr>
</div>
</div>
</ng-template>
</table>
<ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: tree }"></ng-container>
Also: How can I know the Node being dragged and the node it was dropped after? I haven't been able to find an answer anywhere but if I can get these two I might be able to solve it by traversing the tree and doing everything by hand.
Thanks in advance and for getting this far and reading the whole question.
In case some is going through the same problem... I solved this issue passing the node dragged to the drop method by using [cdkDragData]=node since cdk drag and drop is designed for lists, not n-ary trees.
<div [cdkDragData]=node *ngFor="let node of tree; let i=index " cdkDrag>
Then, inside the method one can traverse the tree and do the changes "by hand":
const movedNode: Node = event.item.data; //Node that was dragged
const parentNode: Node = this.dataService.findNode(movedNode.parentId, this.tree[0]); //parent of the dragged node
moveItemInArray(parentNode.children, event.previousIndex, event.currentIndex); //move the node as in any other cdk drag and drop list
Thanks for the answers I received, it really encouraged me to find the best solution 😊