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

13 thoughts on “Angular 7 Drag and Drop example – Angular Material CDK”

  1. Hi @all,
    Is der any way to make a vertical and horizontal list?
    Like that:
    1 2 3 4 5 6
    7 8 9 a b c
    d e f g
    Where i can drag “e” to positon after 4?

    Greetings

  2. i have a scenario that i need to design a card like identity card organization customize the card using drag and drop means putting the name , expiry etc on card which is basically a image how can i utilize it so that it will be used in other page means i set from organization page and resemble the result in the other page after saving the style of it

  3. How can i lock element in position?
    Example:
    I have [a,b,c,d,e] array.
    I want that ‘a’ and ‘b’ to be locked and ‘c’, ‘d’ and ‘e’ can never be before ‘b’ neither ‘a’.

    Thanks

  4. Thanks for the great work man , really appreciate . Looking for the exact code.

    Once again thank you mate. Lot’s of love.

  5. Hi!
    Thanks for amazing explanation
    I just did not understand- how do i get the index of every element in the list after dragging?

    thanks in advance!

  6. Simply desire to say your article is as astounding. The clarity in your post is just great and i can assume you’re an expert on this subject. Fine with your permission let me to grab your feed to keep updated with forthcoming post. Thanks a million and please continue the gratifying work.

  7. I’m not sure exactly why but this site is loading incredibly slow for me. Is anyone else having this issue or is it a issue on my end? I’ll check back later on and see if the problem still exists.

  8. Write more, thats all I have to say. Literally, it seems as though you relied on the video to make your point. You obviously know what youre talking about, why throw away your intelligence on just posting videos to your weblog when you could be giving us something enlightening to read?

Leave a Reply

Your email address will not be published. Required fields are marked *