This content overlaps with a discussion on Angular CDK drag and drop issue inside CSS flexbox.
As mentioned in the aforementioned thread, my suggestion is to establish an items table matrix that mirrors your flex list. For a comprehensive explanation, please refer to this post: 'n'drop-mixed-orientation-in-flex-row-wrap/
I have devised a solution for your issue on StackBlitz, accessible here: https://stackblitz.com/edit/angular-drag-and-drop-in-flex-list
Structure:
<div #rowLayout cdkDropListGroup>
<!-- By assessing the width of the row layout and the item box, you can determine the number of columns per row, initializing an items table matrix accordingly -->
<div
*ngFor="let itemsRow of getItemsTable(rowLayout)"
cdkDropList
class="list"
cdkDropListOrientation="horizontal"
[cdkDropListData]="itemsRow"
(cdkDropListDropped)="reorderDroppedItem($event)"
>
<!-- Dropping reorganizes the items and recalculates the table matrix -->
<div class="box" *ngFor="let item of itemsRow" cdkDrag>
<div class="drag-placeholder" *cdkDragPlaceholder></div>
{{ item }}
</div>
</div>
</div>
CSS Styling:
.box {
width: 33%;
border: solid 1px #ccc;
margin: 1em;
}
.list {
width: 100%;
border: solid 1px #ccc;
height: 90%;
display: flex;
flex-direction: row;
background: white;
border-radius: 4px;
overflow: hidden;
justify-content: space-around;
flex-wrap: wrap;
}
.drag-placeholder {
background: #ccc;
width: 3em;
border: dotted 3px #999;
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
Component Logic:
export class AppComponent {
timePeriods = ["1", "2", "3", "4", "5", "6", "7"];
itemsTable: Array<string[]>;
getItemsTable(rowLayout: Element): string[][] {
if (this.itemsTable) {
return this.itemsTable;
}
// Calculate column size per row
const { width } = rowLayout.getBoundingClientRect();
const boxWidth = Math.round(width * .33); // 33% as specified in css
const columnSize = Math.round(width / boxWidth);
// Determine row size: length of items / column size
// Adding 0.5 ensures rounding up to display last element on new row
const rowSize = Math.round(this.timePeriods.length / columnSize + .5);
// Create table rows
const copy = [...this.timePeriods];
this.itemsTable = Array(rowSize)
.fill("")
.map(
_ =>
Array(columnSize) // fills until the end of column size, hence...
.fill("")
.map(_ => copy.shift())
.filter(item => !!item) // ... removal of empty items is necessary
);
return this.itemsTable;
}
reorderDroppedItem(event: CdkDragDrop<number[]>) {
// Clone table as it requires re-initialization after dropping
let copyTableRows = this.itemsTable.map(_ => _.map(_ => _));
// Handle item drop
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
);
}
// Update items post-drop
this.timePeriods = this.itemsTable.reduce((previous, current) =>
previous.concat(current)
);
// Re-initialize table
let index = 0;
this.itemsTable = copyTableRows.map(row =>
row.map(_ => this.timePeriods[index++])
);
}
}