Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cdkDragHandle in angular material mat-table has no effect

I want to know if it is possible to have a cell that contains a mat-icon defined as

cdkDragHandle.At the moment it is active on the full row but I just want the single icon to be used as draghandle

This is part of the code I'm using:

<mat-table #table [dataSource]="dataSource" class="mat-elevation-z8" 
cdkDropList [cdkDropListData]="dataSource"
(cdkDropListDropped)="dropTable($event)">

<ng-container matColumnDef="Order">
  <mat-header-cell *matHeaderCellDef>
    Actions
  </mat-header-cell>
  <mat-cell mat-cell *matCellDef="let element">
    <mat-icon class="dragCursor" cdkDragHandle>reorder</mat-icon>
    {{element.order}}
    <button mat-icon-button (click)="onDeleteClick(element)">
      <mat-icon>delete</mat-icon>
    </button>
  </mat-cell>
</ng-container>

... more column definitions

<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns;" cdkDrag    [cdkDragData]="row" cdkDragLockAxis="y"></mat-row>

I also tried to define the draghandle on the mat-cell to no avail. Does anybody know how this can be solved?

Thanks in advance!

like image 893
DaanF Avatar asked Nov 14 '18 19:11

DaanF


1 Answers

It seems that cdkDragHandle doesn't work for mat-table.

Tested with latest Angular Material version, v. 9.1.0.

This bug was also discussed on Github, where I've found the following solution: https://github.com/angular/components/issues/13770#issuecomment-506182564 - author ajp76054.

I've used it in my project and it seems to work ok.

I'll post it here for those who will need it:


Initialize the table with cdkDragDisabled property set to true, in order to disable the whole drag container. This allows the user to still interact with the table cells until they are ready to drag the row.

Then on the drag handle element (<mat-icon>), use (mousedown) event to set the cdkDragDisabled to false. Then, reset it to true inside the (cdkDropListDropped) event handler.

So, in the template use the following code:

<mat-table 
   #table 
   [dataSource]="dataSource" 
   cdkDropList 
   (cdkDropListDropped)="drop($event)" 
   cdkDropListData="dataSource" 
   [cdkDropListDisabled]="dragDisabled">

 ...

 <ng-container matColumnDef="order">
   <mat-header-cell *matHeaderCellDef>Order</mat-header-cell>
   <mat-cell *matCellDef="let element"> 
    <mat-icon class="dragCursor" (mousedown)="dragDisabled = false;">reorder</mat-icon>
   </mat-cell>
 </ng-container>

 ...

 <mat-row *matRowDef="let row; columns: displayedColumns;" cdkDrag [cdkDragData]="row"></mat-row>


</mat-table>

And in component ts file:

export class TableBasicExample {
  dragDisabled = true;

  drop(event: CdkDragDrop<any[]>) {
    // Return the drag container to disabled.
    this.dragDisabled = true;

    // other code on drop event
    // 
    const previousIndex = this.dataSource.findIndex((d) => d === event.item.data);

    moveItemInArray(this.dataSource, previousIndex, event.currentIndex);
this.table.renderRows();
  }

}

Working example

https://stackblitz.com/edit/angular-materials-table-with-drag-and-drop-nvyyy4

like image 97
andreivictor Avatar answered Oct 31 '22 11:10

andreivictor