How to implement drag and drop with Angular 9

Jenish Patel

Apr 23, 2020 | 7 min read

How to implement drag and drop with Angular 9

Component Development Kit (CDK)

The Component Development Kit is a set of tools that implement common behaviors and components with very unique interaction styles without being opinionated about the template choices. It is a kind of abstraction of the Angular Material Library, with no styling specific to material design. It provides more unique ways to get creative while building your angular components.

Drag and Drop Tool

The Drag and Drop tool is one of the component development kit common behaviors. It contains directives that enable really top notch drag and drop capabilities on component parts.

The @angular/cdk/drag-drop module provides you with a way to easily and declaratively create drag-and-drop interfaces, with support for free dragging, sorting within a list, transferring items between lists, animations, touch devices, custom drag handles, previews, and placeholders, in addition to horizontal lists and locking along an axis.

Prerequisites

  • The latest version of Angular (use version 9)

// run the command in a terminal to check angular version

ng version
  • Angular application

// run the command below to create new application

ng new drag-and-drop
npm install @angular/cdk@latest


After the successful install angular cdk, we will add "DragDropModule" in "app.module.ts" so it is available for use in the Angular Application like so:

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { DragDropModule } from '@angular/cdk/drag-drop';

@NgModule({import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';


  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    DragDropModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Create a List to render data

Drag and Drop works mostly on array items, let’s create a list of pop movies and then add the drag and drop functionality to it.

  • Open the "app.component.ts" file and add an array of movies like so:
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})

export class AppComponent {
  title = 'my-drag-drop';
  movies = [
    'Episode I - The Phantom Menace',
    'Episode II - Attack of the Clones',
    'Episode III - Revenge of the Sith',
    'Episode IV - A New Hope',
    'Episode V - The Empire Strikes Back',
    'Episode VI - Return of the Jedi',
    'Episode VII - The Force Awakens',
    'Episode VIII - The Last Jedi'
  ];
}
  • Then add a little bit of styling in the "app.component.scss" file like this:
.example-list {
  width: 500px;
  max-width: 100%;
  border: solid 1px #ccc;
  min-height: 60px;
  display: block;
  background: white;
  border-radius: 4px;
  overflow: hidden;
}

.example-box {
  padding: 20px 10px;
  border-bottom: solid 1px #ccc;
  color: rgba(0, 0, 0, 0.87);
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  box-sizing: border-box;
  cursor: move;
  background: white;
  font-size: 14px;
}

.cdk-drag-preview {
  box-sizing: border-box;
  border-radius: 4px;
  box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
              0 8px 10px 1px rgba(0, 0, 0, 0.14),
              0 3px 14px 2px rgba(0, 0, 0, 0.12);
}

.cdk-drag-animating {
  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

.example-box:last-child {
  border: none;
}

.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

.example-custom-placeholder {
  background: #ccc;
  border: dotted 3px #999;
  min-height: 60px;
  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
  • In the "app.component.html" file, replace the boilerplate HTML code with the ngFor command to render the movies list.
<div class="example-box" *ngFor="let movie of movies">
   <div class="example-custom-placeholder" *cdkDragPlaceholder></div>
   {{movie}}
 </div>

Now,we have our list of movies styled and rendered the way it can be easily seen when we drag list items around.

Now we have a list set up, we’ll go through Basic Drag and Drop and Transferring Items between Lists of the new drag and drop tool in the component development kit below:

Basic Drag and Drop

Just by adding the cdkDrag directive to a list item renderer, the list items becomes draggable.

Now that we can drag list items within a list, we can go further by re-ordering items or basically trying to move list items up and down a list. This involves listening for a cdkDropListDropped event and specifying moveItemsInArray method to bring the re-ordering to life.

  • Update the "app.component.html" file with this:
<div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)">

  <div class="example-box" *ngFor="let movie of movies" cdkDrag>
    <div class="example-custom-placeholder" *cdkDragPlaceholder></div>
    {{movie}}
  </div>
  
</div>
  • Update the app.component.ts file with this:
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';

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

The MoveItemsInArray method takes three parameters:

  • The list array where it would do the sort work
  • "event.previousIndex" which is the previous index of the dragged item to drop.
  • "event.currentIndex" which is the current index where the dragged item is being dropped so it can do the swap.

Check the working demo link.

Transferring Items between lists

  • The cdkDropList directive supports transferring dragged items between two or more lists.
  • You can connect one or more cdkDropList instances together by setting the cdkDropListConnectedTo property or by wrapping the elements in an element with the cdkDropListGroup attribute.

Make below changes in your angular application.

  • Update the "app.component.html" file with this:
<div cdkDropListGroup>
  <div class="example-container">
    <h2>Still Doing</h2>

    <div
      cdkDropList
      [cdkDropListData]="todo"
      class="example-list"
      (cdkDropListDropped)="drop($event)">
      <div class="example-box" *ngFor="let item of todo" cdkDrag>{{item}}</div>
    </div>
  </div>

  <div class="example-container">
    <h2>Done</h2>

    <div
      cdkDropList
      [cdkDropListData]="done"
      class="example-list"
      (cdkDropListDropped)="drop($event)">
      <div class="example-box" *ngFor="let item of done" cdkDrag>{{item}}</div>
    </div>
  </div>
</div>

Dissection of what we did:

  • We added a new droplist. where we render a new list.
  • We wrapped the two droplist divs in a div.
  • We specified the droplist data for each list.
  • we created IDs on the drop lists to tell Angular these are separate drop lists.

  • Update the app.component.ts file with this:
import { Component } from '@angular/core';
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  title = 'my-drag-drop';
  movies = [
    'Episode I - The Phantom Menace',
    'Episode II - Attack of the Clones',
    'Episode III - Revenge of the Sith',
    'Episode IV - A New Hope',
    'Episode V - The Empire Strikes Back',
    'Episode VI - Return of the Jedi',
    'Episode VII - The Force Awakens',
    'Episode VIII - The Last Jedi'
  ];

  todo = [
    'Get to work',
    'Pick up groceries',
    'Go home',
    'Fall asleep'
  ];

  done = [
    'Get up',
    'Brush teeth',
    'Take a shower',
    'Check e-mail',
    'Walk dog'
  ];

  drop(event: CdkDragDrop<string[]>) {
    if (event.previousContainer !== event.container) {
      transferArrayItem(event.previousContainer.data, event.container.data,
        event.previousIndex, event.currentIndex)
    } else {
      moveItemInArray(this.movies, event.previousIndex, event.currentIndex);
    }
  }
}

Dissection of what we did:

  • We created a new array and filled it with data.
  • We added if else statement to modify the moving item Array method.
  • The if part contains logic for when a list item is dragged into a separate drop list
  • The else part contains the old logic for basic drag and drop list items in its own list.

  • Update the "app.component.scss" file with this:
.example-container {
  width: 400px;
  max-width: 100%;
  margin: 0 25px 25px 0;
  display: inline-block;
  vertical-align: top;
}

.example-list {
  border: solid 1px #ccc;
  min-height: 60px;
  background: white;
  border-radius: 4px;
  overflow: hidden;
  display: block;
}

.example-box {
  padding: 20px 10px;
  border-bottom: solid 1px #ccc;
  color: rgba(0, 0, 0, 0.87);
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  box-sizing: border-box;
  cursor: move;
  background: white;
  font-size: 14px;
}

.cdk-drag-preview {
  box-sizing: border-box;
  border-radius: 4px;
  box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
              0 8px 10px 1px rgba(0, 0, 0, 0.14),
              0 3px 14px 2px rgba(0, 0, 0, 0.12);
}

.cdk-drag-placeholder {
  opacity: 0;
}

.cdk-drag-animating {
  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

.example-box:last-child {
  border: none;
}

.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
  transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

Dissection of what we did:

  • We added transition styling to the dragging and dropping process.

Check the working demo link.

Conclusion

In this blog we were introduced to the new Angular 7 CDK tool called drag and drop, we saw practical example of how it can be work and the possibilities it affords for a wonderful user experience. You can take a look at the CDK docs here. Happy Coding!


Third Rock Techkno is a leading IT services company. We are a top-ranked web, voice and mobile app development company with over 10 years of experience. Client success forms the core of our value system.

We have expertise in the latest technologies including angular, react native, iOs, Android and more. Third Rock Techkno has developed smart, scalable and innovative solutions for clients across a host of industries.

Our team of dedicated developers combine their knowledge and skills to develop and deliver web and mobile apps that boost business and increase output for our clients.