Drag and Drop in Angular 2 using Native HTML5 API

Before I start, I have to come clean — up until very recently I had no idea about the inner workings of drag and drop, I always pulled down a library that did it all for me and I was golden. So in the quest for knowledge I set out to learn how I could do it in vanilla Javascript. I am not going to explain that here but this is a great resource to learn about it.

Now that I had learnt a little about the DnD API, I was wondering how I could implement the same in Angular 2 and this is what I came up with (github). I used Angular CLI to quickly get an application going.

To demonstrate implementing DnD I decided to build the ever so useful ToDo app. It would use DnD to arrange the to-do items in an order. With some quick component scaffolding and hacking, I had a bare-bone todo app up. For the purposes of this post, I only implemented displaying and ordering the todo items and did not bother implementing creating or completing them.

I decided to create two directives, one to make an element/component draggable (makeDraggable) and the other one to signify that an element/component is a drop target (makeDroppable). The makeDraggable directive wires up the dragstart and dragend events.

The directive accepts an input. This input is used as the data payload in the dragstart event. I assumed I would be able to use application/json as the MIME type and pass the object but that did not work. So I converted the object to a string using JSON.stringify and passed it in using the MIME type text. Also, looks like the draggable attribute cannot be added to custom elements so I added it to the inner li.

The makeDroppable directive wires up the dragenter, dragleave, dragover and drop events.

The drop event gets the data and then emits the dropped event passing in the data.

These directives are then added to the todo components in the todo-list component:

Things to note:

  • Pass the `todo` object to be used as the data.
  • When the `dropped` event is fired, pass the `$event` object and the current `todo` item.

The onDrop event looks like this:

Things to note:

  • If the element is moved down, increment the `order` of the elements from the target to the source by 1.
  • If it was moved up, decrement by 1.
  • Set the source element’s order to the target’s.

And that’s it. Add some styles to pretty up and you have a half decent, homegrown, drag and drop working. Please let me know if this could be done better.

Here is the working plunk:

And here’s the source code

Note: The HTML5 Drag and Drop API is only supported in the newer browsers. Check MDN for the supported browsers.