material drag實現table內拖曳效果

黃宇涵 Joanna Huang 2019/12/02 12:00:28
79

前言

本篇主要介紹實作material table內的欄位拖曳用法, 利用Angular-Material的Component Dev Kit 裡的drag drop 和 table component 進行實作效果。

 

介紹

Angular Material

利用angular去實作出Material的設計樣式, Material樣式由google推出的一套能適應行動裝置和網頁各平台的設計風格, 一種針對網格布局、轉場動畫、深度效果、光影與變化呈現的統一規範,官網請點這裡

 

CDK

組合開發工作包裡面有許多工具用來實現組件之間交互作用的模式, 而不包含原本material 的樣式在內, 也就是說你可以自己客製化組件並加入CDK 的Api同樣可以達到Angular Material組件的互動效果,以下將會以drag drop cdk api進行示範。

 

用法

操作步驟

  1. 實作一個table component
  2. 載入dragdrop module
  3. 加入cdk 已提供的Directives
  4. 綁定觸發事件
  5. 呼叫方法
  6. 更新data source執行結果

 

以下是會使用到的cdk api :

CDK Directives - drag drop

CdkDropList

CdkDrag

 

CDK interfaces - drag drop

CdkDragDrop

CdkDragStart

 

CDK Functions - drag drop

moveItemInArray

 

實作

1. 撰寫一個table範例, 要呈現的表格資料帶入datasource, 接下來先載入dragdrop module。

         <mat-table #table [dataSource]="dataSource" class="mat-elevation-z8">       
                <ng-container matColumnDef="position">
                    <mat-header-cell *matHeaderCellDef> No. </mat-header-cell>
                    <mat-cell *matCellDef="let element"> {{element.position}} </mat-cell>
                </ng-container>         
                <ng-container matColumnDef="name">
                    <mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
                    <mat-cell *matCellDef="let element"> {{element.name}} </mat-cell>
                </ng-container>     
                <ng-container matColumnDef="weight">
                    <mat-header-cell *matHeaderCellDef> Weight </mat-header-cell>
                    <mat-cell *matCellDef="let element"> {{element.weight}} </mat-cell>
                </ng-container>        
                <ng-container matColumnDef="symbol">
                    <mat-header-cell *matHeaderCellDef> Symbol </mat-header-cell>
                    <mat-cell *matCellDef="let element"> {{element.symbol}} </mat-cell>
                </ng-container>
                <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
                <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
            </mat-table>
import { DragDropModule } from '@angular/cdk/drag-drop';
@NgModule({
  imports: [
    DragDropModule,
    CommonModule,
]})

2. table加入directive cdkDropList(含有被拖拉的元素容器), cdkDrag(可以被拖拉的元素), cdkDragDrop(拖曳後放開元素會觸發的事件), cdkDragStart(開始拖曳後會觸發的事件)

           <mat-table cdkDropList (cdkDropListDropped)="dropFunc($event)" #table [dataSource]="dataSource" class="mat-elevation-z8">       
                <ng-container matColumnDef="position">
                    <mat-header-cell *matHeaderCellDef> No. </mat-header-cell>
                    <mat-cell *matCellDef="let element"> {{element.position}} </mat-cell>
                </ng-container>         
                <ng-container matColumnDef="name">
                    <mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
                    <mat-cell *matCellDef="let element"> {{element.name}} </mat-cell>
                </ng-container>     
                <ng-container matColumnDef="weight">
                    <mat-header-cell *matHeaderCellDef> Weight </mat-header-cell>
                    <mat-cell *matCellDef="let element"> {{element.weight}} </mat-cell>
                </ng-container>        
                <ng-container matColumnDef="symbol">
                    <mat-header-cell *matHeaderCellDef> Symbol </mat-header-cell>
                    <mat-cell *matCellDef="let element"> {{element.symbol}} </mat-cell>
                </ng-container>
                <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
                <mat-row cdkDrag (cdkDragStarted)="startFunc($event, row)" *matRowDef="let row; columns: displayedColumns;"></mat-row>
            </mat-table>

3. 接著抓取當前拖曳的元素的index與在觸發的事件中取得currentIndex帶入moveItemInArray function裡 其參數如下表所示,最後得到拖曳後新的列表並更新datasource。

  startFunc(event, row) {
    this.dragIndex = this.dataList.findIndex(data => data.position == row.position);
  }
  dropFunc(event) {
    moveItemInArray(this.dataList, this.dragIndex, event.currentIndex);
    this.dataSource = new MatTableDataSource<Element>(this.dataList);
  }

 

成果

 

drag

結語

本篇介紹可以快速簡單實作出一個可拖曳的table範例,除了上述所說的directive官方還提供許多其他的很實用的directive 像是 cdkDragPreview, cdkDragPlaceholder 和其他的interfaces而有不同的拖曳效果,請參考 https://material.angular.io/cdk/drag-drop/api 有更多完整的範例。

 

黃宇涵 Joanna Huang