Angular 7 Drag and Drop example – Angular Material CDK

angular-7-drag-drop-example-meterial-cdk-feature-image

The @angular/cdk/drag-drop module helps us drag single item or sort it within a horizontal/vertical list, transfer items between lists, show animations, previews, placeholders, custom drag handles. In this tutorial, we’re gonna create many simple examples that show you how to work with Angular 7 Material CDK – Drag and Drop.

Related Post: Angular 7 Virtual Scroll example – Angular Material CDK

Setup Angular 7 Material CDK

– Run cmd:
npm install @angular/material @angular/cdk

– Import DragDropModule into NgModule:

...
import { DragDropModule } from '@angular/cdk/drag-drop';

@NgModule({
  declarations: [...],
  imports: [
    ...
    DragDropModule
  ],
  ...
})
export class AppModule { }

Angular 7 Drag and Drop item

Basic

Add the cdkDrag directive to element to make them draggable:

<div class="drag-box" cdkDrag>
  drag me
</div>

angular-7-drag-drop-example-basic-dragable

Lock Direction

Set cdkDragLockAxis on cdkDrag to restrict dragging:

<div class="drag-box" cdkDragLockAxis="y" cdkDrag>
  only up/down
</div>
<div class="drag-box" cdkDragLockAxis="x" cdkDrag>
  only left/right
</div>

angular-7-drag-drop-example-lock-direction

Event Handler

Add functions on cdkDrag to handle events:
cdkDragStarted: emits when user stops dragging.
cdkDragEnded: emits when user starts dragging.
cdkDragMoved: emits when user is dragging the item (for every pixel).

<div cdkDrag class="drag-box"
  (cdkDragStarted)="dragStarted($event)"
  (cdkDragEnded)="dragEnded($event)"
  (cdkDragMoved)="dragMoved($event)"
>
  drag me
</div>
<p>{{state}} {{position}}</p>

implement the functions:

import { CdkDragEnd, CdkDragStart, CdkDragMove } from '@angular/cdk/drag-drop';
...
export class DragComponent implements OnInit {
  state = '';
  position = '';
  ...

  dragStarted(event: CdkDragStart) {
    this.state = 'dragStarted';
  }

  dragEnded(event: CdkDragEnd) {
    this.state = 'dragEnded';
  }

  dragMoved(event: CdkDragMove) {
    this.position = `> Position X: ${event.pointerPosition.x} - Y: ${event.pointerPosition.y}`;
  }
}

angular-7-drag-drop-example-event-handler

With a Handle

If we want to restrict the draggable area by a handle element, just add cdkDragHandle directive to an element inside of cdkDrag:

<div class="drag-box-with-handler" cdkDrag>
  <div class="box-handler" cdkDragHandle>
    gkz
  </div>
</div>

angular-7-drag-drop-example-with-handle

Angular 7 Drag & Drop items in a List

Basic Sorting List

Cover a set of cdkDrag elements by cdkDropList will automatically rearrange the list when an element moves. To update that list, we listen cdkDropListDropped event:

<div class="box-list" cdkDropList (cdkDropListDropped)="drop($event)">
  <div class="drag-box" *ngFor="let customer of customers" cdkDrag>
    {{customer.name}}
  </div>
</div>

We use drag-and-drop CDK moveItemInArray function to move an item and to calculate the new index of the dropped item inside the array:

import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
...
export class SortListComponent implements OnInit {
  customers = [
    { name: 'Adam', age: 23 },
    { name: 'Jack', age: 27 },
    { name: 'Katherin', age: 26 },
    { name: 'John', age: 30 },
    { name: 'Watson', age: 42 },
  ];

  drop(event: CdkDragDrop<string[]>) {
    moveItemInArray(this.customers, event.previousIndex, event.currentIndex);
  }
}

angular-7-drag-drop-example-basic-sort-list

Horizontal List

By default, cdkDropList directive make the list vertical. We can change by setting the orientation property to "horizontal".

<div
  class="box-list-horizontal"
  cdkDropList
  cdkDropListOrientation="horizontal"
  (cdkDropListDropped)="drop($event)">
  <div class="drag-box" *ngFor="let customer of customers" cdkDrag>
    {{customer.name}}
  </div>
</div>

angular-7-drag-drop-example-horizontal-list

Animations

To set up your animations, we define a transition that targets transform property.
drag-and-drop CDK supports animations while:
– sorting an element inside a list => .cdk-drag

.cdk-drag {
    transition: transform 300ms ease;
}

angular-7-drag-drop-example-animation-sort-list

– animating it from the position we dropped it to final place in the list => .cdk-drag-animating

.cdk-drag-animating {
    transition: transform 300ms ease;
}

angular-7-drag-drop-example-animation-sort-list-simple

Placeholder

Default placeholder

Use .cdk-drag-placeholder to show a placeholder element instead of the real element as it’s being dragged inside a cdkDropList. By default, this will look exactly like the element that is being sorted.

.cdk-drag-placeholder {
    background: #ccc;
    border: dotted 1px #999;
    transition: transform 500ms ease;
}

angular-7-drag-drop-example-placeholder

Custom placeholder

Using *cdkDragPlaceholder directive, we can replace default placeholder with a custom one:

.box-custom-placeholder {
    height: 20px;
    width: 120px;
    background: #fff;
    border: dotted 1px #0084ff;
    transition: transform 200ms ease;
}

.box-list.cdk-drop-list-dragging .drag-box:not(.cdk-drag-placeholder) {
    transition: transform 500ms ease;
}

angular-7-drag-drop-example-custom-placeholder

With Preview

When a cdkDrag element is picked up and dragged, a preview element could be visible. By default, the element looks exactly like the element that is being dragged.
We use .cdk-drag-preview to define preview CSS:

.cdk-drag-preview {
    box-shadow: 0 3px 3px -3px #0084ff;
}

We also need to provide a custom template using *cdkDragPreview:

<div cdkDropList class="box-list" (cdkDropListDropped)="drop($event)">
  <div class="drag-box" *ngFor="let customer of customers" cdkDrag>
    {{customer.name}}
    <p *cdkDragPreview>Age: {{customer.age}}</p>
  </div>
</div>

angular-7-drag-drop-example-drag-preview

Angular 7 Drag & Drop between Lists

Basic

We can connect one or more cdkDropList together using cdkDropListConnectedTo property. Then we set cdkDropListData and cdkDragData for associating data with cdkDropList and cdkDrag.

<div
  class="box-list"
  cdkDropList
  #inactiveList="cdkDropList"
  id = "Inactive Customers"
  [cdkDropListData]="inactiveCustomers"
  [cdkDropListConnectedTo]="[activeList]"
  (cdkDropListDropped)="drop($event)">
  <div
    class="drag-box"
    [cdkDragData]="customer"
    *ngFor="let customer of inactiveCustomers" 
    cdkDrag>
    {{customer}}
  </div>
</div>

Implementation of cdkDropListDropped function will use drag-and-drop CDK moveItemInArray and transferArrayItem:

import {
  CdkDragDrop, moveItemInArray, transferArrayItem
} from '@angular/cdk/drag-drop';

...
export class TransferItemsListsComponent {
  inactiveCustomers = [
    'Adam',
    'Jack',
    'Katherin'
  ];

  activeCustomers = [
    'John',
    'Watson'
  ];

  drop(event: CdkDragDrop<string[]>) {
    if (event.previousContainer === event.container) {
      console.log('dropped Event',
        `> dropped '${event.item.data}' into '${event.container.id}'`);
      moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
    } else {
      console.log('dropped Event',
        `> dropped '${event.item.data}' into '${event.container.id}'`);
      transferArrayItem(
        event.previousContainer.data,
        event.container.data,
        event.previousIndex,
        event.currentIndex);
    }
  }
}

angular-7-drag-drop-example-transfer-lists-item

Event Handler with List

Drag Event Handlers

cdkDragStarted: emits when the user starts dragging the item.
cdkDragEnded: emits when the user stops dragging the item.
cdkDragEntered: emits when the item are moved into a new container.
cdkDragExited: emits when dragging the item into another container.

<div
  class="box-list"
  cdkDropList
  #activeList1="cdkDropList"
  id = "Active Customers 1"
  [cdkDropListData]="activeCustomers"
  [cdkDropListConnectedTo]="[inactiveList1]"
  (cdkDropListDropped)="drop($event)">
  <div class="drag-box" [cdkDragData]="customer" *ngFor="let customer of activeCustomers" cdkDrag
    (cdkDragStarted)="dragStarted($event)"
    (cdkDragEnded)="dragEnded($event)"
    (cdkDragEntered)="dragEntered($event)"
    (cdkDragExited)="dragExited($event)">
	{{customer}}
  </div>
</div>

Implementations of the functions:

import {
  moveItemInArray, transferArrayItem,
  CdkDragDrop, CdkDragStart, CdkDragEnd, CdkDragEnter, CdkDragExit
} from '@angular/cdk/drag-drop';
...
export class TransferItemsListsComponent {
  ...

  dragStarted(event: CdkDragStart) {
    console.log('dragStarted Event > item', event.source.data);
  }

  dragEnded(event: CdkDragEnd) {
    console.log('dragEnded Event > item', event.source.data);
  }

  dragEntered(event: CdkDragEnter) {
    console.log('dragEntered Event',
      `> dropping '${event.item.data}' into '${event.container.id}'`);
  }

  dragExited(event: CdkDragExit) {
    console.log('dragExited Event',
      `> drag '${event.item.data}' from '${event.container.id}'`);
  }
}

angular-7-drag-drop-example-transfer-lists-drag-event-handlers

Drop Event Handlers

cdkDropListDropped: emits when an item was dropped inside the container.
cdkDropListEntered: emits when a new item is dragged into this container.
cdkDropListExited: emits when an item is dragged from this container into another container.

<div
  class="box-list"
  cdkDropList
  #inactiveList2="cdkDropList"
  id = "Inactive Customers 2"
  [cdkDropListData]="inactiveCustomers"
  [cdkDropListConnectedTo]="[activeList2]"
  (cdkDropListDropped)="drop($event)"
  (cdkDropListEntered)="dropListEntered($event)"
  (cdkDropListExited)="dropListExited($event)">
  <div
    class="drag-box"
    [cdkDragData]="customer"
    *ngFor="let customer of inactiveCustomers" 
    cdkDrag>
    {{customer}}
  </div>
</div>

Implementations of the functions:

import { CdkDragEnter, CdkDragExit } from '@angular/cdk/drag-drop';

...
export class TransferItemsListsComponent {

  drop(event: CdkDragDrop<string[]>) {
    ...
      console.log('dropped Event',
        `> dropped '${event.item.data}' into '${event.container.id}'`);
  }

  dropListEntered(event: CdkDragEnter) {
    console.log('dropListEntered Event',
      `> dropping '${event.item.data}' into '${event.container.id}'`);
  }

  dropListExited(event: CdkDragExit) {
    console.log('dropListExited Event',
      `> drag '${event.item.data}' from '${event.container.id}'`);
  }
}

angular-7-drag-drop-example-transfer-lists-drop-event-handlers

Source Code

AngularMaterialCDK-Drag-Drop-example

0 0 votes
Article Rating
Subscribe
Notify of
guest
3.4K Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments