Help us understand the problem. What is going on with this article?

Angular v7のDragDropModuleを使ってTrelloっぽいの作ってみた

More than 1 year has passed since last update.

Angular 7.0.0がリリースされましたね 🎉
CDKにDrag and DropのModuleが追加されたので触ってみました。

ドラッグ・アンド・ドロップの機能って自前で開発すると結構めんどくさかったのが、めちゃくちゃ簡単に実装できました👏楽しい👏
DEMO

やったこと

  • app.module.tsDragDropModule をimportする
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { DragDropModule } from '@angular/cdk/drag-drop';

import { AppComponent } from './app.component';

@NgModule({
  imports: [
    BrowserModule,
    DragDropModule
  ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }
  • app.component.tsCdkDragDrop, moveItemInArray, transferArrayItem をimportする
  • ドロップ時のメソッドを定義する
    • event発生したときに、 container が移動前と同じ配列か違う配列かを判定して、 moveItemInArray()transferArrayItem() を実行する
app.component.ts
import { Component } from '@angular/core';
import { 
  CdkDragDrop, 
  moveItemInArray, 
  transferArrayItem 
} from '@angular/cdk/drag-drop';


@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  public todo = [
    '働く',
    '映画を見る',
    '掃除する',
    '洗濯する',
    '飲みに行く',
    '買い物に行く',
    '家に帰る',
    '散歩する',
  ]

  public doing = [
    'サッカーする',
    '野球する',
    'バスケする',
    'テニスする',
  ]

  public done = [
    '本を読む',
    '歯を磨く',
    '昼寝する',
    'メールチェック',
    '犬と遊ぶ'
  ]

  public drop(event: CdkDragDrop<string[]>): void {
    if (event.previousContainer === event.container) {
      moveItemInArray(event.container.data,
                      event.previousIndex,
                      event.currentIndex);
    } else {
      transferArrayItem(event.previousContainer.data,
                        event.container.data,
                        event.previousIndex,
                        event.currentIndex);
    }
  }
}
  • cdkDropListcdkDrag 要素セットの親要素に追加する
  • #todoList="cdkDropList" ←のように cdkDropListへの参照をテンプレート変数化する
  • [cdkDropListConnectedTo]="[doneList]"
    • 移動先としてつなぎたい cdkDropList の参照を指定する
  • cdkDropListDropped イベントは、ドラッグが終了した時に発火するので、 app.component.ts で定義しておいた drop() メソッドを使う
app.component.html
<section class="container">
  <h1>MY TASKS</h1>
  <div class="cards">
    <section class="card">
      <h2>
        TODO
      </h2>
      <ul cdkDropList 
          #todoList="cdkDropList"
          [cdkDropListData]="todo"
          [cdkDropListConnectedTo]="[doingList, doneList]"
          class="list"
          (cdkDropListDropped)="drop($event)">
        <li class="item" *ngFor="let item of todo" cdkDrag>{{item}}</li>
      </ul>
    </section>
    <section class="card">
      <h2>
        DOING
      </h2>
      <ul cdkDropList 
          #doingList="cdkDropList"
          [cdkDropListData]="doing"
          [cdkDropListConnectedTo]="[todoList, doneList]"
          class="list"
          (cdkDropListDropped)="drop($event)">
        <li class="item" *ngFor="let item of doing" cdkDrag>{{item}}</li>
      </ul>
    </section>
    <section class="card">
      <h2>
        DONE
      </h2>
      <ul cdkDropList 
          #doneList="cdkDropList"
          [cdkDropListData]="done"
          [cdkDropListConnectedTo]="[todoList, doingList]"
          class="list"
          (cdkDropListDropped)="drop($event)">
        <li class="item" *ngFor="let item of done" cdkDrag>{{item}}</li>
      </ul>
    </section>
  </div>
</section>

さいごに

実際の機能開発だと、もっとやることあると思いますが、とりあえずUIはこれだけで実装できました。
ライブラリとか使ったり、自前で開発する必要がなさそうなので、とても良いですね。

cf.

y4m4to
渋谷の転職サービスの会社で働くフロントエンド・エンジニア
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away