cdkDragHandle in angular material mat-table has no effect

Viewed 1623

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!

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


Update 2022-05-16

Still an issue in Angular Material v13.

Working example with @angular/cdk & @angular/material - v13.3.7 (also contains the improvement suggested by @Max Leske):

https://stackblitz.com/edit/angular-ivy-gof2zv

Related