I want to use an Observable as the data source for a material drag and drop, but I'm struggling at the moment. Basically I have a list of swimlanes in a kanban board and each swimlane has a bunch of items that I want to move around. When I move an item I want to update the back end as well. Multiple people will also be updating the same kanban board, so I want to use socket.io to automatically move the items around too (which I'm also struggling with for the same reason)
Here's the template:
<button mat-raised-button color="primary" (click)="addItem()">Add Item</button>
<button mat-raised-button color="primary" (click)="moveItem()" style="margin-left:10px">Move Item</button>
<div cdkDropListGroup>
<div class="example-container" *ngFor="let lane of swimlanes">
<h2>{{lane.name}}</h2>
<div
cdkDropList
#doneList="cdkDropList"
[cdkDropListData]="lane.array | async"
class="example-list"
(cdkDropListDropped)="drop($event)">
<div class="example-box" *ngFor="let item of lane.array | async" cdkDrag>{{item.name}}</div>
</div>
</div>
</div>
Here's the component code:
import {Component, OnInit} from '@angular/core';
import {CdkDragDrop, moveItemInArray, transferArrayItem} from '@angular/cdk/drag-drop';
import { Subscription, of, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
export interface Swimlane{
name: string;
array: Observable<Task[]>;
}
export interface Task{
name: string;
list: string;
}
/**
* @title Drag&Drop connected sorting
*/
@Component({
selector: 'cdk-drag-drop-connected-sorting-example',
templateUrl: 'cdk-drag-drop-connected-sorting-example.html',
styleUrls: ['cdk-drag-drop-connected-sorting-example.css'],
})
export class CdkDragDropConnectedSortingExample implements OnInit {
//These will eventually come from an API.
items:Task[] = [
{name: "Get to work", list: "To Do"},
{name: "Pick up groceries", list: "To Do"},
{name: "Go home", list: "To Do"},
{name: "Fall asleep", list: "To Do"},
{name: "Get up", list: "Done"},
{name: "Brush teeth", list: "Done"},
{name: "Take a shower", list: "Done"},
{name: "Check e-mail", list: "Done"},
{name: "Walk dog", list: "Done"}
];
swimlanes:Swimlane[] = [];
//Create Observables as the data sources
itemsObservable:Observable<Task[]>;
todo:Observable<Task[]>;
done:Observable<Task[]>;
ngOnInit(): void {
this.itemsObservable = of(this.items);
this.todo = this.itemsObservable.pipe(
map((item:Task[]) => item.filter((item:Task) => item.list === "Done")
));
this.done = this.itemsObservable.pipe(
map((item:Task[]) => item.filter((item:Task) => item.list === "To Do")
));
this.swimlanes.push({name:"To Do", array: this.todo});
this.swimlanes.push({name:"Done", array: this.done});
}
addItem(){
this.items.push({name: "New Item", list: "To Do"});
console.log(this.items.length);
}
moveItem(){
}
drop(event: CdkDragDrop<string[]>) {
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);
}
}
}
Here's a stackblitz of where I'm trying to use observables as the data source. You can see that it loads the lanes correctly, but when you attempt to move one of the items it dissapears. Any ideas?
In my actual app, I am receiving the values from an API request. So it automatically comes in as an Observable. Which I then break into a local base array and unsubscribe from the Observable. Then I create a new Observable from the local base array and make changes to the local base array in the hope that the changes will reflect in the drag drop. But this isn't currently working.
Happy to write my own move functionality, but without the lanes reflecting changes to the Observable data source, I can't get it to work.