I am making an angular app where I have two lists. From list 'A', I can copy items to list 'B' again and again. The problem is, I want to make the dragged items be added only in between the start and end items in list 'B'. see image
This is what I have tried so far:
HTML:
<mat-drawer-container class="example-container">
<mat-drawer mode="side" opened>
<h3>Create your Workflow</h3>
<h5>Drag and drop the elements to visualize the process.</h5>
<div cdkDropList
#optionsList="cdkDropList"
[cdkDropListData]="options"
[cdkDropListConnectedTo]="[workflowList]"
class="example-list"
cdkDropListSortingDisabled
(cdkDropListDropped)="drop($event)"
[cdkDropListEnterPredicate]="noReturnPredicate">
<div class="example-box" cdkDrag *ngFor="let item of options"> {{item}} </div>
</div>
</mat-drawer>
<mat-drawer-content>
<div cdkDropList
#workflowList="cdkDropList"
[cdkDropListData]="workflow"
[cdkDropListConnectedTo]="[optionsList]"
class="example-list"
(cdkDropListDropped)="drop($event)"
[cdkDropListSortPredicate]="sortPredicate"
>
<div class="example-box" [cdkDragDisabled]="item.disabled" *ngFor="let item of workflow" cdkDragLockAxis="y" cdkDrag>{{item.value}}</div>
</div>
</mat-drawer-content>
.ts -> export class:
options = [
'Step',
'Branch'
];
workflow=[
{value: 'Start', disabled: true},
{value: 'Finish', disabled: true}
];
drop(event: any) {
if (event.previousContainer === event.container) {
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
copyArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex
);
}
}
noReturnPredicate(){
return false;
}
sortPredicate(){
return false;
}
Right now, I can only enter the options after the 'End' in workflow. I want it to be between start and end. Can anyone help, please?
Also, the options name is not showing in the added list, if anyone could guide me on that part too would be really helpful. Thanks
There are two problems:
Both drop lists should have same value type. You've got:
options: string[],
workflow: {value: string, disabled: boolean}[],
So, you should unify types (or write you own copyArrayItem
method which will convert between types):
interface DragItem {
value: string;
disabled: boolean;
}
...
options: DragItem[] = [
{ value: 'Step', disabled: ... },
{ value: 'Branch', disabled: ... }
];
workflow: DragItem[] = [
{ value: 'Start', disabled: true },
{ value: 'Finish', disabled: true }
];
If you want keep index in defined range, check it:
sortPredicate(index: number, drag: CdkDrag, drop: CdkDropList): boolean {
// preliminary check, not reliable
return index > 0 && index < drop.getSortedItems().length;
}
sortPredicate
is actually not reliable (I am able to place items in forbidden positions), you should double check index behaviour in drop event and fix it:
drop(event: CdkDragDrop<DragItem[], any>) {
if (event.previousContainer === event.container) {
moveItemInArray(
event.container.data,
event.previousIndex,
event.currentIndex
);
} else {
let currentIndex = event.currentIndex;
// double check index range
if (0 === currentIndex) {
currentIndex++;
}
if (event.container.getSortedItems().length === currentIndex) {
currentIndex--;
}
copyArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
currentIndex
);
}
}
Working example: https://stackblitz.com/edit/angular-drag-drop-range