material drag實現table內拖曳效果
前言
本篇主要介紹實作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進行示範。
用法
操作步驟
- 實作一個table component
- 載入dragdrop module
- 加入cdk 已提供的Directives
- 綁定觸發事件
- 呼叫方法
- 更新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);
}
成果

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

