Skip to content
⚠️ This article was written in 2018. Some content may be outdated.

Angular CDK Drag-and-Drop Sorting and Virtual Scrolling in Practice

After the official release of Angular 7, the CDK's Drag and Drop and Virtual Scrolling features quickly became the most popular additions. This article provides an in-depth walkthrough with real project examples.

Drag-and-Drop Sorting: Task Board

Installation

bash
npm install @angular/cdk

Single-column Drag Sorting

typescript
{% raw %}
import { DragDropModule } from "@angular/cdk/drag-drop";

@Component({
  selector: "app-sortable-list",
  template: `
    <div cdkDropList class="task-list" (cdkDropListDropped)="drop($event)">
      <div *ngFor="let task of tasks" cdkDrag class="task-item">
        <mat-icon cdkDragHandle>drag_handle</mat-icon>
        <span>{{ task.title }}</span>
        <span class="badge" [ngClass]="task.priority">{{ task.priority }}</span>
      </div>
    </div>
  `,
})
export class SortableListComponent {
  tasks: Task[] = [
    { id: 1, title: "Requirements Analysis", priority: "high" },
    { id: 2, title: "UI Design", priority: "medium" },
    { id: 3, title: "Frontend Development", priority: "high" },
    { id: 4, title: "API Integration", priority: "medium" },
    { id: 5, title: "Testing & Deployment", priority: "low" },
  ];

  drop(event: CdkDragDrop<Task[]>) {
    moveItemInArray(this.tasks, event.previousIndex, event.currentIndex);
    this.saveOrder(); // persist the new order
  }

  saveOrder() {
    const order = this.tasks.map((t, i) => ({ id: t.id, sort: i }));
    this.taskService.updateOrder(order).subscribe();
  }
}
{% endraw %}

Multi-column Kanban Board (Cross-column Dragging)

html
{% raw %}
<div class="kanban-board">
  <div
    *ngFor="let column of columns"
    cdkDropList
    [cdkDropListData]="column.tasks"
    [cdkDropListConnectedTo]="getConnectedLists(column)"
    (cdkDropListDropped)="onDrop($event)"
  >
    <h3>{{ column.title }}</h3>
    <div *ngFor="let task of column.tasks" cdkDrag>{{ task.title }}</div>
  </div>
</div>
{% endraw %}
typescript
onDrop(event: CdkDragDrop<Task[]>) {
  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 task status
    const task = event.container.data[event.currentIndex];
    const newStatus = this.getColumnStatus(event.container.id);
    this.taskService.updateStatus(task.id, newStatus).subscribe();
  }
}

Virtual Scrolling: Large Data Lists

typescript
{% raw %}
@Component({
  template: `
    <cdk-virtual-scroll-viewport
      itemSize="60"
      style="height: 500px; overflow-y: auto"
    >
      <mat-list-item
        *cdkVirtualFor="let item of items; let i = index"
        class="list-item"
      >
        <mat-icon mat-list-icon>person</mat-icon>
        <h4 mat-line>{{ item.name }}</h4>
        <p mat-line>{{ item.email }}</p>
      </mat-list-item>
    </cdk-virtual-scroll-viewport>
  `,
})
export class VirtualUserListComponent {
  // Smooth even with 100,000 items
  items: User[] = generateLargeDataset(100000);
}
{% endraw %}

Key parameters:

  • itemSize: item height in px — best performance with fixed height
  • For variable-height items, use AutoSizeVirtualScrollStrategy (experimental)

Combining Drag-and-Drop with Virtual Scrolling

There is one limitation when combining the two: the DOM nodes generated by cdkVirtualFor are dynamic, and directly combining them with cdkDrag causes offset calculation issues. Recommendation:

  • < 500 items: use *ngFor + cdkDrag directly
  • 500 items: use pagination instead of mixing virtual scrolling with drag-and-drop

Summary

The Angular CDK Drag and Drop module is very well designed — Kanban-style applications require almost no additional code. Virtual scrolling is the go-to solution for large data lists. Mastering these two APIs handles a large share of UI interaction challenges in enterprise applications.

MIT Licensed