Angular Materialでドラッグ&ドロップを実装する(cdk/drag-drop)

#目次
[1.はじめに](#1-はじめに)
[2.フレームワークとライブラリ](#2-フレームワークとライブラリ)
[3.サンプルコード](#3-サンプルコード)
[4.サンプルコードの表示](#4-サンプルコードの表示)
[5.htmlの疑似コード](#5-htmlの疑似コード)
[6.tsの疑似コード](#6-tsの疑似コード)
[7.dropメソッド](#7-dropメソッド)
[8.付録](#8-付録)
[9.注意点](#9-注意点)
[10.参考資料](#10-参考資料)
[11.最後に一言](#11-最後に一言)

<!-- ※リンクを張る場合は #x- までがいるので要注意。 -->
#1. はじめに
<!-- 自己紹介や発端や概要を記載 -->
田中です。近年、WebブラウザのSPA(シングルページアプリケーション)のプラットフォームにて、ドラッグ＆ドロップ機能のライブラリが公式で提供されるようになり、直感的なUIを使えるWebページが、とても作りやすい時代になりました。

そこで今回は、ドラッグ＆ドロップ機能を実現するライブラリのサンプルコードについて、htmlとtsを疑似コード(プログラムの一部を日本語にしたもの)に翻訳してみようと思います。

ゴールは、このような書き方で使えます。ということだけを知ってもらうところですので、気楽に読んでみてください。

※深くは解説していませんのであしからず。m(_ _)m

**※免責事項(必ず、ご一読ください)**
　　本記事の情報により生じた、いかなる損害や損失についても、当社は一切の責任を負いかねます。
　　また、誤情報が入り込んだり、情報が古くなったりすることもありますので、必ずしも正確性を保証するものではありませんのでご了承ください。

#2. フレームワークとライブラリ
今回は**Angular Material**の**cdk/drag-drop**を使用します。
　[Drag and Drop(@angular/cdk/drag-drop)](https://material.angular.io/cdk/drag-drop/overview)

#3. サンプルコード
上記公式サイトのサンプルコード**Transferring items between lists**を使用します。
To Doのリストのアイテムをマウスで左クリックしたまま、Doneのリストに移す動作を実現させます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1661584/eee43c16-f8fe-0c10-f0e4-2ef29d53b209.png)



#4. サンプルコードの表示
＜＞をクリックすることで、HTML、TS、CSSが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1661584/ece00790-7b95-87f1-36c3-53f0f65aaa49.png)

#5. htmlの疑似コード

HTMLのソースコードの大事なところに絞って解読すると下記のようになります。

```ruby:htmlファイルの疑似コード

<div class="コンテナーに適用するcssのスタイル">
<h2>リスト1のタイトル<h2>

 <div
  cdkDropList
  #リスト1="cdkDropList"
  [cdkDropListData]="リスト1に適用するts内の配列"
  [cdkDropListConnectedTo]="[リスト2]"
  class="リスト1に適用するcssのスタイル"
  (cdkDropListDropped)="ドロップ時に動くメソッド"
  <div class="アイテムに適用するcssのクラス" *ngFor="let リスト1のアイテム of リスト1に適用するts内の配列" cdkDrag>{{リスト1のアイテム}}</div>
 </div>
</div>

<div class="コンテナーに適用するcssのスタイル">
<h2>リスト2のタイトル</h2>

  <div
   cdkDropList
   #リスト2="cdkDropList"
   [cdkDropListData]="リスト2に適用するts内の配列"
    [cdkDropListConnectedTo]="[リスト1]"
   class="リスト2に適用するcssのスタイル"
   (cdkDropListDropped)="ドロップ時に動くメソッド"
   <div class="アイテムに適用するcssのクラス"  *ngFor="let リスト2のアイテム of リスト2に適用するts内の配列"cdkDrag>{{リスト2のアイテム}}</div>
  </div>
</div>
```


#6. tsの疑似コード

tsのソースコードも同様に解読してみます。


```ruby:tsファイルの概形
import {Component} from '@angular/core';
import {CdkDragDrop, moveItemInArray, transferArrayItem} from '@angular/cdk/drag-drop';
@Component({
  selector: 'cdk-drag-drop-connected-sorting-example',
  templateUrl: 'cdk-drag-drop-connected-sorting-example.html',
  styleUrls: ['cdk-drag-drop-connected-sorting-example.css'],
})
export class CdkDragDropConnectedSortingExample {
  リスト1の配列 = [
　　～リスト1のアイテムを定義～
  ];
  リスト2の配列 = [
　　～リスト2アイテムを定義～
  ];
  drop(イベント: CdkDragDrop<string[]>) {
　　～dropイベント発生時の処理内容～
　}
}

```



#7. dropメソッド
dropメソッドも解読してみます。eventを使って、dropメソッド内部に閉じた形で書くことができます。

```ruby:dropメソッド
  drop(イベント: CdkDragDrop<string[]>) {
    if (移動前のリスト === 移動先のリスト) {
      moveItemInArray(移動先のリスト, 移動前のリスト,移動先のリストにおけるアイテムの内部的な番号);
    } else {
      transferArrayItem(移動前のリスト,
                        移動先のリスト,
                        移動前のリストにおけるアイテムの内部的な番号,
                        移動先のリストにおけるアイテムの内部的な番号);
    }
  }
```

#8. 付録
上記のサンプルコードを改造して、CdkDragDropのリストの中にCdkDragDropのリストといった、多重構造のドラッグ＆ドロップ可能なリストを作ってみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1661584/f5eb7b8e-6d59-501c-2e06-e76331df7618.png)
なお、試して分かったことなのですが、子のリストのアイテムを別の親のリストにドロップすることはできませんでした。
そのようなことをする場合、同様なJSフレームワークの「**Vue**」の「**Vue.Draggable**」ライブラリを使うとよいようなので、こちらも後学のため、勉強してみたいと思います。

　著者：rito様
　URL：[Vue.jsでドラッグアンドドロップによる要素の並べ替えと移動を実装する](https://www.ritolab.com/entry/173)


#9. 注意点
・リストの中のアイテムを構造体で定義する場合、プロパティ名は**"id"**以外を使用してください。
　listのプロパティに**id: number**を使用した場合
　　　ドラッグ＆ドロップ後に、idが自動で昇順に置き換わり、意図しない動作となります。
　listのプロパティに**identity: number**を使用した場合
　　　こうすることで、ドラッグ＆ドロップ後も、アイテムからみた固有識別番号が変化しません。

```ruby:構造体定義例
export interface Hero {
  identity: number;
  name: string;
}
```
#10. 参考資料
- [Angular Material cdkDropList（英語ページ）](https://material.angular.io/cdk/drag-drop/overview)
- [DROP WITH THE NEW ANGULAR MATERIAL CDK（英語ページ）](https://timdeschryver.dev/blog/exploring-drag-and-drop-with-the-new-angular-material-cdk)

#11. 最後に一言
　最後まで読んでいただき、ありがとうございます！　今後も新しいWeb技術を取り込んでいこうと思います。