Exploring Drag and Drop with the new Angular Material CDK
I’ve heard that Angular Material had a new drag and drop CDK in their upcoming version. Now with the first Angular and Angular Material release candidate being released, I think it’s time to explore some of the new stuff. I’m really looking forward to this and I’m assuming you’re too, so let’s not waste any time and let’s get started. We’ll start of with a simple example and build our way up to a simple task board.
Let’s start by exploring the API with the simplest example I can think of, a div that can be dragged and dropped.
The first step is to install Angular Material and since this isn’t a released version we have to install it by specifying its version:
This post is edited at 2018–10–09 to be compatible with @email@example.com. In this release the cdk-drop component is been refactored to a cdkDrop directive. It also prefixes all the input and output properties with cdkDrop, e.g. data becomes cdkDropData. These modifications streamlines the whole API and gives us as developers more power over it. https://github.com/angular/material2/pull/13441
Next, we can import the
DragDropModule into our module:
Now that we’ve imported the module we can create our first draggable component by using the
If we run the code we can now already drag and drop the div. Pretty neat, right?
Now that we know how to drag an element, the next step is to create a drop zone. For this we’ll use a new directive
cdkDrop, it will act as a container to drop the draggable items. If we try to drop an item outside the drop zone, it will go back to its original position inside the drop zone.
Now that we know how to create a draggable item and a drop zone, the next step is to drag and re-order items inside a list. We’ll use the
*ngFor directive to create the list elements inside a
The items are defined in the
AppComponent as a string array:
The GIF below demonstrates that the items inside are re-ordering themselves automatically while we’re dragging them. But when we drop an item it goes back to its original position.
To solve this problem and save the new index when we drop an item inside the list, we’ll have to implement a
cdkDropDropped function. The
dropped function gets invoked every time when the user drops an item inside the drop zone. Its signature looks as follows:
As you can see in the code snippet above, the drag and drop CDK also comes with a utility function
moveItemInArray. This function is used to calculate the new index of the dropped item inside the array, rad!
Now that we have an implementation of the
dropped function, it’s time to bind it to the
cdkDrop element inside the HTML.
Resulting in draggable and re-ordering items inside the
All this within minutes of our initial set-up without basically writing a single line of code.
Let’s take it a step further and create the simple task board.
To do this, we’ll split up the
items array into three smaller arrays; one for the new items, the second for the active items, and the last one for the items that are done.
We need to display three separate lists and for each list we’ll create its own drop zone. We can bind the arrays to a drop zone by using the
[cdkDropConnectedTo] input property we can connect a
cdkDrop list instance to another instance of a
cdkDrop list. If we don’t do this, we won’t be able to drag and drop the items to another list.
In our task board example these are the connections we have to make:
newlist to the
activelist to the
donelist to the
In other words, you can drag a
new item to
done, and in reversed order. But you can’t drag a
new item to the
done list without passing through the
active list. Combined this gives the following result:
The last step is to make our
dropped function smarter, in order to fulfill our needs it has to move the items from one list to another list.
When the container is the same, it re-orders the items as before. If the container is different, it moves the dragged item to the list where the item is being dropped in. Here again, a utility function,
transferArrayItem, is provided out of the box.
An important part here is that you can write your own implementation for
transferArrayItem if you have a use case that is more complex. You don’t have to use these built-in functions from the CDK.
Another use case is to cancel a drop, e.g. for some reason an item isn’t allowed to be moved. To do this you can just short-circuit inside the
Another part of the drag and drop API is knowing when an item is being added to the drop zone and when an item has been removed from the drop zone. This can be done with the
cdkDropExited functions, both are events on the
cdkDrop element, just like
cdkDropDropped as we’ve seen before.
Bind your item state with the
[cdkDragData] input property.
In the examples above we simply have some text as our items, but imagine having cards as draggable items. It might not be that usable or pretty to drag those big cards across the columns. Luckily the drag and drop CDK also provides a way to create a preview of the card while dragging it. This is possible with the
As you can see in the GIF, the new items have “New item: Item” as state. When we start dragging the item, it’s using the
*cdkDragPreview template. In our case this is simply the name of the item, but this can be customized to your needs.
enterPredicate property on the
cdkDrop element, it is possible to specify a boolean-valued function which gets invoked when an item enters the drop zone. By using this functionality, an item can be allowed (or denied) in the drop zone. As example we have the use case below, which decides whether an item can be dropped in the
And in the HTML template:
The above GIF demonstrates that it’s only possible to drop
Item 2 inside the
done list, and only when there are at least 2 other items inside the
I’m really looking forward to use this API in an upcoming project. Therefore I explored the API once the release candidate came out and I’m very pleased with the result. It’s very easy and intuitive to use, but at the same time it’s flexible by giving you the opportunity to be in control when you need to.
If you’re as excited as I am, you can find more information in the beta documentation and the in source code of course.
The example used in this post can be found and be played with on StackBlitz.
Please consider supporting me if have you enjoyed this post and found it useful: