Thank you for reading my blog posts, I am no longer publishing new content on this platform. You can find my latest content on either mainawycliffe.dev or All Things Typescript Newsletter (✉️)
In this post, we are going to take a close look at the drag and drop feature coming to Angular 7 Content Development Kit (CDK). We are getting closer to the release of Angular 7, so it is only fair to see what is in store for us. You can learn more about angular 7 here.
So, to checkout this feature, we will be creating a barebone to-do application. We will use the drag and drop, to move items from our to-do list to the done or cancelled lists. Our to-do application will have three lists, to-do items, done items and cancelled items. To cancel an item, you move it from either of the other two lists to the cancelled items.
The same process is applied when moving an item from to-do item to done or cancelled list. You can also move items back and forth. You should also be able to re-arrange the list as you see fit by moving items up or down easily. For this app, we won’t persist items to keep thing simple, so everything will be lost when you reload. For the UI we will use bootstrap, but you can use any UI library or framework you want to.
So, without further ado:
For this project, we will be using the release candidate (RC) version of Angular 7. This is latest version of Angular 7 as of the time am writing this. This means, we also need the same version of Angular CLI to generate an Angular 7 application. You can upgrade your global version of Angular CLI or install it in a directory and generate your new angular project from that directory. Since the local version of Angular CLI supersedes the global version, then any new project generated in that directory will use Angular 7. To learn more about how to install pre-release version of Angular 7, check the last section of the following article.
First, let’s create and navigate to a new directory to test out angular 7 using terminal or PowerShell. Then install a local version of pre-release version of Angular CLI using your favorite package manager Yarn:
$ yarn add @angular/[email protected]
// or with npm
$ npm install @angular/[email protected]
Then, generate a new project using Angular CLI just you normally would:
$ ng new ng-material7-drag-and-drop-demo
Then change directory to that directory and add dependencies we require for this project: Yarn
$ yarn add @angular/[email protected] bootstrap
// or with npm
$ npm install @angular/[email protected] bootstrap
Now, let’s create our to-do application:
First, we need import the DragDropModule
from Angular CDK into our app module.
...
import { DragDropModule } from '@angular/cdk/drag-drop';
...
@NgModule({
declarations: [AppComponent],
imports: [
//...
DragDropModule,
// ...
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
Next, let’s create an interface for our to-do list. Generate the interface using Angular CLI.
$ ng generate interface todo
Next, open the newly created typescript file and add the following content:
export interface Todo {
title: string;
dateAdded: string;
}
NB: This is a simple to-do application, so no need to make it too complicated, hence it has the title of the to-do and the date it was added only.
First, we need three lists, which we shall add as properties of the class: todo, done and cancelled. We shall initialize the first to with some initial to-do and done items:
public todo: Todo[] = [
{ title: 'Get to work', dateAdded: new Date().toString() },
{ title: 'Pick up groceries', dateAdded: new Date().toString() },
{ title: 'Go home', dateAdded: new Date().toString() },
{ title: 'Fall asleep', dateAdded: new Date().toString() }
];
public done: Todo[] = [
{ title: 'Get up', dateAdded: new Date().toString() },
{ title: 'Brush teeth', dateAdded: new Date().toString() },
{ title: 'Take a shower', dateAdded: new Date().toString() },
{ title: 'Check e-mail', dateAdded: new Date().toString() },
{ title: 'Walk dog', dateAdded: new Date().toString() }
];
public cancelled: Todo[] = [];
Next, we need a method to add new items to either the to-do or done lists:
addItem(list: string, todo: string) {
if (list === 'todo') {
this.todo.push({ title: todo, dateAdded: new Date().toString() });
} else {
this.done.push({ title: todo, dateAdded: new Date().toString() });
}
}
And finally, a method that will be triggered when you drag and drop an item from one list to another.
drop(event: CdkDragDrop<Todo[]>) {
// first check if it was moved within the same list or moved to a different list
if (event.previousContainer === event.container) {
// change the items index if it was moved within the same list
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
// remove item from the previous list and add it to the new array
transferArrayItem(event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex);
}
}
NB: The above method, either transfers an item between two arrays (lists) or moves a to-do item up or down in the array. First, you need to determine whether the user moved the content to another list, let’s say from to-do to done or they just re-arranged the items by moving an item up or down within the array. It uses the previousContainer and currentContainer properties to determine that. If the two are the same, then the user just re-arranged the list and not moving them. Then you use the
transferArrayItem
to move items to a different array, andmoveItemInArray
to move items within the same array.
We are using Bootstrap for the UI but feel free to use any UI Framework you are comfortable with. So, first we need to add some input controls to add new items to our to-do list:
<div class="row">
<div class="col-6">
<div class="form-group">
<label>New Task</label> <input #todoitem class="form-control" />
</div>
</div>
<div class="col-6">
<div class="form-group">
<label>List</label>
<select #todolist class="form-control">
<option selected value="todo">To Do</option>
<option value="done">Done</option>
</select>
</div>
</div>
<div class="col-12 text-right">
<button
(click)="addItem(todolist.value, todoitem.value)"
class="btn btn-primary"
>
Add Item
</button>
</div>
</div>
Next, let’s add drag and drop list to our template. For this, we will be using the cdk-drop to wrap around each of our lists (to-do, done and cancelled list). We will pass the following properties:
#todoList
) – the id of the drag and drop list[data]
) – the data source of the list i.e. to-do, cancelled and done arrays,[ConnectedTo]
) – This sets limits to which lists the user can drag and drop items to.(dropped)
.So, our first list for to-do items will look like this. We are using *ngFor
directive to display the actual list inside the drag and drop list.
<!-- to-do items list -->
<cdk-drop
class="list-group list-group-flush"
#todoList
[data]="todo"
[connectedTo]="[doneList, cancelledList]"
(dropped)="drop($event)"
>
<div
class="list-group-item list-group-item-primary"
*ngFor="let item of todo"
cdkDrag
>
<p class="mb-1">{{ item.title | titlecase }}</p>
<small class="text-muted"> {{ item.dateAdded | date:'short' }}</small>
</div>
</cdk-drop>
And the same goes for done and cancelled lists:
<!-- Done to-do items list -->
<cdk-drop
#doneList
[data]="done"
[connectedTo]="[todoList, cancelledList]"
class="list-group list-group-flush"
(dropped)="drop($event)"
>
<div
class="list-group-item list-group-item-success"
*ngFor="let item of done"
cdkDrag
>
<p class="mb-1">{{ item.title | titlecase }}</p>
<small class="text-muted"> {{ item.dateAdded | date:'short' }} </small>
</div>
</cdk-drop>
<!-- Cancelled to-do items list -->
<cdk-drop
#cancelledList
[data]="cancelled"
[connectedTo]="[todoList, doneList]"
class="list-group list-group-flush"
(dropped)="drop($event)"
>
<div
class="list-group-item list-group-item-warning"
*ngFor="let item of cancelled"
cdkDrag
>
<p class="mb-1">{{ item.title | titlecase }}</p>
<small class="text-muted"> {{ item.dateAdded | date:'short' }} </small>
</div>
</cdk-drop>
And finally, you can now wrap each of those drag and drop lists with a bootstrap card component:
<div class="card bg-warning">
<div class="card-header text-white"><h2>Cancelled</h2></div>
<!-- Lists Here -->
</div>
You can find the complete template here.
You can find the demo for the above project here and the source code here.
Angular Component Development Kit (CDK) is a set of un-opinionated developers’ tools to add common interaction behavior to your angular UI …
Read MoreIn this demo, we will build an angular autocomplete component that gets autocomplete suggestions from a http service such as a REST API. The …
Read MoreUI Libraries and Frameworks make it easier for developers to build clean and consistent User Interfaces (UI). They provide components, …
Read MoreAngular material has a very nice date picker but while its functionality can accommodate a lot of developers, sometimes it just falls short. …
Read MoreOne of the least talked about features of Angular 6 is Angular CLI Workspaces. Workspaces or Angular CLI Workspaces give angular developers …
Read MoreIcons are a necessity when building modern-day web apps and sometimes they can be frustrating. While icon sets like Font Awesome and …
Read More