ComponentDevKit(DragAndDrop)を使ってみる

# はじめに

この記事は[Angular Advent Calendar 2018](https://qiita.com/advent-calendar/2018/angular)の8日目の記事です

Angular7がリリースされてComponentDevKitにDragAndDropが入ってきました

ということで簡単なTODOアプリを作ってみます

# CDKとは

簡単に言うと一般的なWebアプリケーションで使うUIを提供してくれるライブラリ群です

少ないコード記述量・短時間で必要な機能を構築できます

Angular公式が作っているので安心感がありますね

# 動作環境

```
$ npx ng --version

     _                      _                 ____ _     ___
    / \   _ __   __ _ _   _| | __ _ _ __     / ___| |   |_ _|
   / △ \ | '_ \ / _` | | | | |/ _` | '__|   | |   | |    | |
  / ___ \| | | | (_| | |_| | | (_| | |      | |___| |___ | |
 /_/   \_\_| |_|\__, |\__,_|_|\__,_|_|       \____|_____|___|
                |___/


Angular CLI: 7.0.2
Node: 9.3.0
OS: linux x64
Angular: 7.0.0
... animations, common, compiler, compiler-cli, core, forms
... http, language-service, platform-browser
... platform-browser-dynamic, router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.10.2
@angular-devkit/build-angular     0.10.2
@angular-devkit/build-optimizer   0.10.2
@angular-devkit/build-webpack     0.10.2
@angular-devkit/core              7.0.2
@angular-devkit/schematics        7.0.2
@angular/cdk                      7.0.1
@angular/cli                      7.0.2
@angular/material                 7.0.1
@ngtools/webpack                  7.0.2
@schematics/angular               7.0.2
@schematics/update                0.10.2
rxjs                              6.3.3
typescript                        3.1.3
webpack                           4.19.1

```

# install,project作成

cliでnewすると対話形式でいくつか質問される(7から)ので答えます

```
$ npx ng add @angular/cdk
$ npx ng add @angular/material
+ @angular/material@7.0.1
added 68 packages in 14.639s
Installed packages for tooling via npm.
? Enter a prebuilt theme name, or "custom" for a custom theme: indigo-pink
? Set up HammerJS for gesture recognition? Yes
? Set up browser animations for Angular Material? Yes
```

# materialの雛形追加

とりあえずナビだけ

```
npx ng g @angular/material:material-nav --name side-nav
```

# サーバ起動

```
npx ng s
```

# 実装

準備が整ったのでTODOリストを作っていきます

ドキュメントは下記

[Drag and Drop | Angular Material](https://material.angular.io/cdk/drag-drop/overview)

[https://material.angular.io/cdk/drag-drop/overview:embed:cite]

サンプルにすでにそれっぽく動かせるコードがあるのでそこからすこし手を加えてTODOリストを作ってみます

- サンプル

[Drag&Drop connected sorting - StackBlitz](https://stackblitz.com/angular/mrlygxvavkm?file=app%2Fcdk-drag-drop-connected-sorting-example.ts)

[https://stackblitz.com/angular/mrlygxvavkm?file=app%2Fcdk-drag-drop-connected-sorting-example.ts:embed:cite]

- テンプレート側

`#todoList="cdkDropList"` でテンプレート変数にディレクティブのインスタンスを代入

`[cdkDropListConnecedTo]="[doneList]"`でどの箱とつながっているかを定義

配列になっているので複数記述できる感じですね

サンプルだと箱が2つなのでもう片方の箱のインスタンスを指定しています

`[cdkDropListData]="todo"`で対象の箱の初期データを渡しています

データの内容はtsファイルの方に記述されています

- `(cdkDropListDropped)`

`cdkDropList`配下の`cdkDrag`の要素に対するドラッグが終わったらイベントを受け取るようになっています

`drop`関数では対象のタスクが同じ箱内で順番だけが変わった場合は`moveItemInArray`

別の箱へ移動した場合は`transferArrayItem`を呼び出してそれぞれ適切なデータをとってきて移動させています

めちゃくちゃわかりやすい！

今回はこのサンプルに下記追加してみます

- doingのリスト
- タスクの追加機能
- タスクの削除機能

## doingのリスト

- 他2つの箱にならって箱を追加

- 各箱の`cdkDropListConnecedTo`を3つ相互に接続させるように修正

これだけですね

## データの追加

テキストフィールドを用意してクリックイベントで対象データ(todo)に追加するだけ

- todo-list.component.ts

```
  addTask(task: string): void {
    this.todo.push(task);
  }
```

- todo-list.component.html

```
  <mat-form-field class="example-full-width">
    <input #task matInput placeholder="Task" value="task">
  </mat-form-field>
  <button mat-stroked-button color="primary" (click)="addTask(task.value)">Add</button>
```

あとはAngular側がよしなにやってくれます

## データの削除

こちらも対象のデータから削除するだけ

- todo-list.component.ts

```
  deleteTask(data: any[], index: number): void {
    data.splice(index,1);
  }
```

- todo-list.component.html

```
    <div class="example-box" *ngFor="let item of doing; let i=index" cdkDrag>
      {{item}}
      <button mat-icon-button color="warn" (click)="deleteTask(doing,i)">
        <mat-icon aria-label="Example icon-button with a heart icon">
          delete
        </mat-icon>
      </button>
    </div>
```

最終的にこんな感じになりました

![cdk-dnd01.gif](https://qiita-image-store.s3.amazonaws.com/0/20020/d2df90fd-4eae-4c61-268e-90ab3df8074a.gif)

# まとめ

なんて楽なんだ！という印象でした

ドラッグアンドドロップのUIは1から実装ってなるとちょっと気が重くなる感じのイメージだったのですがCDKを使って実装すれば簡単に実装できそうです

これ使って自分用にTODO作るか！っていうくらい簡単でした

CDKは他にも色々機能があるので調べて使ってみたいと思います

今後さらに増えてくれることに期待してます

今回使ったサンプルのコードは下記に置きました

[swfz/todo-sample: angular todo list](https://github.com/swfz/todo-sample)

[https://github.com/swfz/todo-sample:embed:cite]