Reputation: 1289
I have a To Do List which leverages Angular Material's cdkDrag
directive on elements inside of a cdkDropList
. Marking items as 'to-do' or 'done' and vice versa is straightforward.
There's a level of detail in the user interaction, namely, a page refresh, which results in items not necessarily being in the order in which they were dragged.
Take this example in which a user is assigned 3 tasks: eat breakfast, eat lunch, eat dinner:
The user doesn't like that priority and decides to tackle his/her eating assignments in this order instead. The drag and drop interactions take place and the To Do list is finalized as:
On page refresh, that's where the gotcha kicks in. It goes back into the original state of:
eat breakfast, eat lunch, eat dinner
When it clearly should be:
eat dinner, eat breakfast, eat lunch
This observation holds true as well for items marked as done.
What is the missing piece I need to acknowledge the current state of this interaction. Do note, this implementation is based on How To Build an App With Drag and Drop With Angular
Thanks for your time.
Upvotes: 1
Views: 4646
Reputation: 1
here's an approach I have encountered the same problem. I am creating a kanban board with to manage task and to change its status by drag and drop cdk so here's what I did:
html
Tasks To Do<div class="example-container">
<h2 style="text-align: center;">Tasks In Progress</h2>
<div
cdkDropList
[cdkDropListData]="progresslist"
class="example-list"
(cdkDropListDropped)="drop($event)">
<div (click)=" openDialogAssign(item.taskId,item)" style="background-color: #78C0E0;"class="example-box" *ngFor="let item of progresslist" cdkDrag> <app-boarditem
[item]="item" ></app-boarditem></div>
</div>
</div>
<div class="example-container">
<h2 style="text-align: center;">Tasks To Be Tested</h2>
<div
cdkDropList
[cdkDropListData]="testedslist"
class="example-list"
(cdkDropListDropped)="drop($event)" >
<div (click)=" openDialogAssign(item.taskId,item)" style="background-color: #F8E290;" class="example-box" *ngFor="let item of testedslist" cdkDrag> <app-boarditem
[item]="item" ></app-boarditem></div>
</div>
</div>
<div class="example-container">
<h2 style="text-align: center;">Tasks Done</h2>
<div
cdkDropList
[cdkDropListData]="donelist"
class="example-list"
(cdkDropListDropped)="drop($event)">
<div (click)=" openDialogAssign(item.taskId,item)" style="background-color: rgb(173, 233, 173);" class="example-box" *ngFor="let item of donelist" cdkDrag> <app-boarditem
[item]="item" ></app-boarditem></div>
</div>
</div>
typescript:
drop(event: CdkDragDrop<any[]>) { if (event.previousContainer === event.container) { moveItemInArray( event.container.data, event.previousIndex, event.currentIndex );
} else {
transferArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex
);
// console.log("ahayhayhy",event.container.id);
console.log( event.container.data[event.currentIndex.valueOf()] );
var taskupdatedStatus:any= event.container.data[event.currentIndex.valueOf()]
// console.log("dattttttttttta",event.container.data);
// x.itemId=index
switch (event.container.id) {
case "cdk-drop-list-0":
{console.log("set to todo");
this.taskservice.changeTaskStatus(taskupdatedStatus.taskId,"todo",taskupdatedStatus).subscribe(res=>{
console.log("task updated to todo",res);
console.log(taskupdatedStatus);
})
}
break;
case "cdk-drop-list-1":
console.log("set to inprogress");
console.log(taskupdatedStatus);
this.taskservice.changeTaskStatus(taskupdatedStatus.taskId,"prog",taskupdatedStatus).subscribe(res=>{
console.log("task updated to prog",res);
console.log(taskupdatedStatus);
})
break;
case "cdk-drop-list-2":
console.log("set to test");
console.log(taskupdatedStatus);
this.taskservice.changeTaskStatus(taskupdatedStatus.taskId,"test",taskupdatedStatus).subscribe(res=>{
console.log("task updated to test",res);
console.log(taskupdatedStatus);
})
break;
case "cdk-drop-list-3":
console.log("set to DONE");
console.log(taskupdatedStatus);
this.taskservice.changeTaskStatus(taskupdatedStatus.taskId,"done",taskupdatedStatus).subscribe(res=>{
console.log("task updated to done",res);
console.log(taskupdatedStatus);
})
break;
default:
console.log("neiver");
break;
}
}
}
this is the line that i implemented to capture the element i just dropped so that i can access its attributs
var taskupdatedStatus:any= event.container.data[event.currentIndex.valueOf()]
Upvotes: 0
Reputation: 57999
You need convert you array of "strings" in an array of "object"
Imagine you has an array of items like
[{task:"eat breakfast",order:0},
{task:"eat lunch",order:1},
{task:"eat dinner",order:2}
]
In your drop function you need re-calculate the property order. using the typical drop function
drop(event: CdkDragDrop<any[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
transferArrayItem(event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex);
//if transfer, recalculate the order of previous (the list from drag)
event.previousContainer.data.forEach((x,index)=>{
x.order=index
})
}
//always, recalculate the order of the container (the list to drag)
event.container.data.forEach((x,index)=>{
x.order=index
})
}
Then you need save the data in anyway (I think you can use the ngOnDestroy), when you recived the data don't forget sort by order
NOTE: In this SO there're are a cdkDragList using a formArray (only for sorting) if you want use a FormArray but it's not necesary, just with two arrays must be enougth
Upvotes: 5