Angular Drag and Drop - The Best Way
In this post you will learn how to implement drag and drop inside Angular.
Just from the start I want to say that drag n drop is not an easy feature and I highly recommend you to use a library for that. Previously I made a post about drag n drop inside React. The mail problem there was that a lot of libraries were obsolete and it was difficult to find a library which implements drag n drop effectively.
We don't have such problem inside Angular because we have an awesome Angular Material and we don't even need to look for alternatives.
Angular Material is supported by Angular itself, it is always up to date with the latest Angular and you can be sure that this library won't be obsolete.
Inside Angular Material we have 2 things. First of all we have lots of different components but also we have an Angular CDK. It means that we don't get any styling or components but just full business logic and functions that we can use for our needs. And drag and drop is one of such functions.
Which actually means that we don't need some component but just logic of dragging, dropping this is why we must install Angular CDK and not Angular Material.
npm i @angular/cdk
Our project
What we want to implement is a sortable list. So we can drag the items of the list and sort them. The only thing that I prepared for our project is a file data.ts
which has a list of users that we want to sort.
export const data = [
{
id: 1,
name: 'Samaria',
},
{
id: 2,
name: 'Gauthier',
},
{
id: 3,
name: 'Mellisa',
},
{
id: 4,
name: 'Arabela',
},
{
id: 5,
name: 'Devon',
},
{
id: 6,
name: 'Stacee',
},
{
id: 7,
name: 'Federica',
},
{
id: 8,
name: 'Jecho',
},
{
id: 9,
name: 'Alasteir',
},
{
id: 10,
name: 'Elston',
},
];
We will use this data to render a list and sort it. Additionally to this data.ts
I have an interface for each user.
export interface UserInterface {
id: number;
name: string;
}
Our first step will be to get this list of data inside our component.
import { data } from './data';
export class AppComponent {
users: UserInterface[] = data;
}
Our next step will be to add all necessary dependencies that we need inside this component in order to implement drag n drop.
import {
CdkDrag,
CdkDragDrop,
CdkDropList,
CdkDropListGroup,
} from '@angular/cdk/drag-drop';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
standalone: true,
imports: [
RouterOutlet,
RouterLink,
CommonModule,
CdkDropListGroup,
CdkDropList,
CdkDrag,
],
})
export class AppComponent {
....
}
Here we added CdkDrag
, CdkDropList
, CdkDropListGroup
and CdkDragDrop
. These are all directives that we need in our component.
Writing markup
Our next step is to write some markup.
<div cdkDropListGroup class="users-container">
<div
cdkDropList
[cdkDropListData]="users"
class="users-list"
(cdkDropListDropped)="drop($event)"
>
<div *ngFor="let user of users" cdkDrag class="user">{{ user.name }}</div>
</div>
</div>
Here we created a cdkDropListGroup
which is our main container. Inside we created a cdkDropList
where we provided our users
as an array in cdkDropListData
. Also we have a callback cdkDropListDropped
which happens after we do drag and drop. Inside this list container we are rendering just a normal list but on each item we attach cdkDrag
directive.
We also wrote several classes and we need to write some styling for our elements.
.users-container {
width: 400px;
max-width: 100%;
margin: 0 25px 25px 0;
display: inline-block;
vertical-align: top;
}
.users-list {
border: solid 1px #ccc;
min-height: 60px;
background: white;
border-radius: 4px;
overflow: hidden;
display: block;
}
.user {
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;
}
.user:last-child {
border: none;
}
.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);
}
.users-list.cdk-drop-list-dragging .user:not(.cdk-drag-placeholder) {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
Here we styled not only our elements but several classes which are added by CDK itself. All these styles will make our drag understandable and clear for user because of placeholders, animations and shadows.
Adding drop functions
Previously we provided drop
function inside our markup but we didn't create this function yet.
export class AppComponent {
users: UserInterface[] = data;
drop(event: CdkDragDrop<UserInterface[]>): void {
moveItemInArray(
event.container.data,
event.previousIndex,
event.currentIndex
);
}
}
Inside drop
we get an event with all needed information. Like what element we are dragging and with what index we need to swap it. Luckily for us we don't need to move elements in the array ourselves. With moveItemInArray
function which CDK provides we can define where we need to move element. It does all heavy lifting for us and will update our list of users.
As you can see in browser our drag and drop is fully implemented with all necessary styling.
Want to conquer your next JavaScript interview? Download my FREE PDF - Pass Your JS Interview with Confidence and start preparing for success today!
📚 Source code of what we've done