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.
A simple example link
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:
format_quoteThis post is edited at 2018–10–09 to be compatible with @angular/material@7.0.0-rc.1. 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 cdkDrag
directive.
If we run the code we can now already drag and drop the div. Pretty neat, right?
Creating a drop zone link
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.
Re-ordering items inside a list link
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 cdkDrop
container.
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 cdkDrop
container.
format_quoteAll this within minutes of our initial set-up without basically writing a single line of code.
Dragging from one list to another list link
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 cdkDropData
input.
Connecting the lists (drop zones) link
With 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:
- the
new
list to theactive
list; - the
active
list to thenew
anddone
list; - the
done
list to theactive
list;
In other words, you can drag a new
item to active
, from active
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 moveItemInArray
and 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 dropped
function.
Extra's link
Extra 1: Output events, intercepting when an item is Entered
and Exited
link
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 cdkDropEntered
and 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.
Extra 2: Creating animations when an item is being dragged and dropped link
The CDK ships with a couple of useful classes for you to use in order to style your draggable items and to animate certain transitions, e.g. when you’re re-ordering the items inside a list.
Extra 3: Creating a preview while dragging the item link
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 *cdkDragPreview
directive.
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.
Extra 4: Allowing an item to be dropped in the drop zone link
With the 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 done
list.
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 active
list.
Time to wrap it up link
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.
Feel free to update this blog post on GitHub, thanks in advance!
Join My Newsletter (WIP)
Join my weekly newsletter to receive my latest blog posts and bits, directly in your inbox.
Support me
I appreciate it if you would support me if have you enjoyed this post and found it useful, thank you in advance.