0

I'm building and app where there are multiple items rendered in set of columns. (For sake of demonstration let's say 4 columns)

I'm trying to achieve functionality of dragging and dropping items onto each other which will result in merge of those two items.

typescricpt data structure

Details{
     id:number;
     columns:Column[];
}

Column{
     id:number;
     item:Item[];
}
Item{
     id:number;
     text:string;
}

So I have details component with :

<div fxLayout="row wrap" fxLayoutAlign="center" fxLayoutGap="5px" cdkDropListGroup>
  <column *ngFor="let column of details.columns" [column]="column" fxFlex>
  </column>
</div>

And column component:

<div>
    Column Header
</div>
<div cdkDropList 
     (cdkDropListDropped)="drop($event)" 
     [cdkDropListData]="column.items"
     *ngFor="let item of column.items">
  <item cdkDrag [item]="item" [cdkDragData]="item">
  </item>
</div>

For now I just print it

drop(event: CdkDragDrop<Item[]>) {
   console.log(event);
}

Whenever I now print event after drop , I do have details of current container and moved onto , but I would require information about where exactly ( on which item.id ) I dropped that element, and not make item evade as default cdkDragDrop behaves. Afterwards I would have events for merging stuff on backend etc.

And hints would be appreciated

Link to example in stackblitz

Khobar
  • 486
  • 7
  • 20

1 Answers1

1

I was able to find solution.

Collegue of mine proposed to pass item on which event occurred in drop(event)

So final solution would be :

<div cdkDropList 
     (cdkDropListDropped)="drop($event,item)" 
     [cdkDropListData]="column.items"
     *ngFor="let item of column.items">
  <item cdkDrag [item]="item" [cdkDragData]="item">
  </item>
</div>

and handling ( using lodash )

drop(event: CdkDragDrop<Item[]>, dropedOn: Item) {
    const dragged = event.item.data;
    if (dragged.id != dropedOn.id) {
        dropedOn.text = dropedOn.text + "\n" + dragged.text;
        if (event.previousContainer === event.container) {
            _.remove(event.container.data,(item)=>item.id== dragged.id);
        } else {
           _.remove(event.previousContainer.data,(item)=>item.id== dragged.id);
        }
     }
  }

Updated stackblitz.

However the whole solution was still bit too clunky , and it was hard to clearly show which element was to be merged into and eventually moved to other sollution ng-drag-drop.

There every item is draggable and droppable and effect is bit nicer ( although requires extra searching of item to delete it from column)

<div *ngFor="let item of column.items;" style="margin-top: 2px">
    <div draggable [dragData]="item" droppable (onDrop)="onItemDrop($event,item)">
            <item [item]="item"></item>
    </div>
</div>

And updated stackblitz with other solution

Khobar
  • 486
  • 7
  • 20