Exploring Drag and Drop with the new Angular Material CDK

profile
Tim Deschryver
timdeschryver.dev

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_quote

This 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_quote

All 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:

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.

Buy Me a Coffee at ko-fi.com PayPal logo

Share this post