To implement a cdkDropList for each word, my approach involves using an outer div and an inner div as the draggable element. Additionally, I have set the size of the outer div to remain fixed so that when dragging occurs, there is no re-ordering of the words; instead, it leaves an empty space where the word was dragged from.
You can view the outcome in this StackBlitz project
<div #contenedor class="categories" cdkDropListGroup>
<ng-container *ngFor="let item of items; let i=index">
<div class="categories-item" cdkDropList
cdkDropListOrientation="horizontal"
[cdkDropListData]="{item:item, index:i}"
(cdkDropListDropped)="drop($event)">
<div class="inner" cdkDrag>
<div *cdkDragPlaceholder></div>
<div class="categories-item-drag" *cdkDragPreview matchSize="true">
<div class="inner">{{item}}</div>
</div>
{{item}}
</div>
</div>
</ng-container>
</div>
I am utilizing an observable that returns an array of words. In the `subscribe` method, I assign each word to the item variable and then use a `setTimeout()` function to add the size to the outer div.
export class AppComponent implements OnInit {
@ViewChildren(CdkDropList, { read: ElementRef }) pills: QueryList<ElementRef>;
constructor(private renderer: Renderer2) {}
items: any[];
positions: any[];
ngOnInit() {
this.getParragraf().subscribe(res => {
this.items = res;
setTimeout(() => {
this.pills.forEach(x => {
this.renderer.setStyle(
x.nativeElement,
"width",
x.nativeElement.getBoundingClientRect().width + "px"
);
});
});
});
}
drop(event: CdkDragDrop<any>) {
this.items.splice(event.previousContainer.data.index, 1);
this.items.splice(event.container.data.index,0,event.previousContainer.data.item)
}
getParragraf() {
return of(
"Let him who walks in the dark, who has no light, trust in the name of the Lord and rely on his God.".split(
" "
)
);
}
}
Updated: You do not necessarily need to create a cdkDropListGroup, as you can utilize [cdkDropListConnectedTo] property. To achieve this, make use of two arrays: words and items
If 'res' is an array of strings, you can do the following:
this.items = res.map((x, index) => ({ value: x, ok: false, id: 'id' + index }));
this.words = res.map(x => ({ o: Math.random(), value: x }))
.sort((a, b) => a.o - b.o)
.map(x => (
{
value: x.value,
connected: this.items.filter(w => x.value == w.value).map(x => x.id)
}))
Then, use 'item.value', 'item.id', 'word.value', and 'word.connected'
Check out the updated StackBlitz example