Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reorder mat-table rows with angular material's drag-and-drop

Angular 7 brought the powerful DragDropModule with it: https://material.angular.io/cdk/drag-drop/examples

The documentation deals with rearranging items within lists or transferring items between several lists. However, it doesn't talk about tables.

I was wondering whether there is a comfortable way of using angular material's drag-and-drop system for reordering rows in mat-table or cdk-table.

(You can add cdkDropList to mat-table which makes the mechanism work but without all the fancy animations and default drag placeholders.)

Does something like an easy-to-implement default for sorting table rows via drag-and-drop exist?

like image 486
David Brem Avatar asked Nov 19 '18 15:11

David Brem


3 Answers

The styling is done by CSS (look at the CSS tab on the example page). I tweaked it to work with mat-table:

.cdk-drag-preview {   box-sizing: border-box;   border-radius: 4px;   box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),               0 8px 10px 1px rgba(0, 0, 0, 0.14),               0 3px 14px 2px rgba(0, 0, 0, 0.12); }  .cdk-drag-placeholder {   opacity: 0; }  .cdk-drag-animating {   transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); }  .cdk-drop-list-dragging .mat-row:not(.cdk-drag-placeholder) {   transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); } 

I placed this in my main styles.scss file.


For anyone wondering how to implement drag and drop on a mat-table, you need to:

  1. Add cdkDropList to mat-table
  2. Add (cdkDropListDropped)="onListDrop($event)" to mat-table
  3. Add cdkDrag to mat-row

onListDrop will look something like:

onListDrop(event: CdkDragDrop<string[]>) {   // Swap the elements around   moveItemInArray(this.myArray, event.previousIndex, event.currentIndex); } 

moveItemInArray is an Angular Material function. You can import it.

like image 175
Lee Gunn Avatar answered Sep 18 '22 15:09

Lee Gunn


Found example https://stackblitz.com/edit/angular-igmugp

Looks the missing part is

this.table.renderRows();
like image 22
Grebets Kostyantyn Avatar answered Sep 21 '22 15:09

Grebets Kostyantyn


I was using MatTableDataSource for my dataSource so my solution was this:

  • Importing DragDropModule in component.module.ts

  • Importing CdkDragDrop in the component

  • Adding @ViewChild('table') table: MatTable<any>; to the component.ts.

  • In the HTML add:

    <table mat-table #table [dataSource]="dataSource" class="mat-elevation-z8"
      cdkDropList
      [cdkDropListData]="dataSource"
      (cdkDropListDropped)="drop($event)">
    
  • At the *matRowDef you need to add this :

    <tr mat-row *matRowDef="let row; columns: displayedColumns;"
      cdkDrag 
      [cdkDragData]=row>
    </tr>
    
  • Then in the component.ts I made the drop event:

    drop(event: CdkDragDrop<Scene[]>) {
      const previousIndex = this.dataSource.data.findIndex(row => row === event.item.data);
      moveItemInArray(this.dataSource.data,previousIndex, event.currentIndex);
      this.dataSource.data = this.dataSource.data.slice();
    }
    
like image 40
Paul Ochon Avatar answered Sep 20 '22 15:09

Paul Ochon