使用角材料的拖放重新排列垫表行

Posted

技术标签:

【中文标题】使用角材料的拖放重新排列垫表行【英文标题】:Reorder mat-table rows with angular material's drag-and-drop 【发布时间】:2019-04-21 23:30:03 【问题描述】:

Angular 7 带来了强大的 DragDropModule:https://material.angular.io/cdk/drag-drop/examples

文档涉及重新排列列表中的项目或在多个列表之间转移项目。但是,它没有谈论表格。

我想知道是否有一种舒适的方法可以使用 angular material 的拖放系统来重新排序 mat-table 或 cdk-table 中的行。

(您可以将cdkDropList 添加到mat-table,这使机制工作,但没有所有花哨的动画和默认的拖动占位符。)

是否存在类似于通过拖放对表格行进行排序的易于实现的默认设置?

【问题讨论】:

您描述了该机制正在工作。对我来说,使用实际的角度 7.1 不起作用。当我将 cdkDropList 添加到 mat-table 时,我总是收到 Uncaught TypeError: Cannot read property 'clientRect' of undefined. 【参考方案1】:

样式由 CSS 完成(查看示例页面上的 CSS 选项卡)。我对其进行了调整以使用 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);

我把它放在我的主 style.scss 文件中。


对于想知道如何在 mat-table 上实现拖放的任何人,您需要:

    cdkDropList 添加到mat-table(cdkDropListDropped)="onListDrop($event)" 添加到mat-tablecdkDrag 添加到mat-row

onListDrop 看起来像:

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

moveItemInArray 是一个 Angular Material 函数。你可以导入它。

【讨论】:

除此之外,别忘了将 DragDropModule 添加到您的 NgModule 中,如提到的 here 目前有一个问题,event.previousIndex 只能在第一次工作。解决方法是在mat-row 上使用[cdkDragData]=rowpreviousIndex = this.myDataSource.findIndex(row =&gt; row === event.item.data) 我做到了这一点,但我无法添加拖动手柄。有没有人设法使这项工作?谢谢! 使用链接中 github 问题中的 cdkrootelement 建议,我能够在拖动手柄方面取得相当大的进展。然而,在桌子上触摸滚动是行不通的。当您将项目拖动到屏幕边缘时,自动滚动也不会。 @EthanMelamed 你能展示一下你是如何用 cdkrootelement 解决它的吗?我找不到你提到的问题。【参考方案2】:

找到例子https://stackblitz.com/edit/angular-igmugp

看起来缺少的部分是

this.table.renderRows();

【讨论】:

有什么方法可以得到 currentIndex 吗?列克:const prevIndex = this.dataSource.findIndex((d) => d === event.item.data); 这个样本就像一个魅力!请注意表格组件底部的cdkDrag [cdkDragData]="row" 定义......它实际上使行可拖动【参考方案3】:

我使用MatTableDataSource 作为我的数据源,所以我的解决方案是这样的:

component.module.ts 中导入DragDropModule

组件

中导入CdkDragDrop

@ViewChild('table') table: MatTable&lt;any&gt;; 添加到component.ts

html 中添加:

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

*matRowDef 你需要添加这个:

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

然后在component.ts我做了drop事件:

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();

【讨论】:

【参考方案4】:

我在 stackblitz 上找到了一个很好的例子:https://stackblitz.com/edit/table-drag-n-drop

为了不破坏拖放预览的用户界面,请使用标签

<mat-table>...</mat-table>
<mat-header-cell>...</mat-header-cell>
<mat-cell>...</mat-cell>
<mat-header-row>...</mat-header-row>
<mat-row>...</mat-row>

而不是

<table mat-table>...</table mat-table>
<th mat-header-cell>...</th mat-header-cell>
<td mat-cell>...</td mat-cell>
<tr mat-header-row>...</tr mat-header-row>
<tr mat-row>...</tr mat-row>

结合https://***.com/a/53630171/12331146中提到的css,对我来说是完美的解决方案。

【讨论】:

我同意!使用 和相关标签 + Lee Gunn 的 CSS 效果完美!【参考方案5】:

如果您仍在使用table 而不是mat-table 来呈现表格。您可以考虑手动设置表格上每个td 列的宽度。

在https://trungk18.com/experience/angular-cdk-drag-drop-list-table/上查看完整的解释和stackblitz

.col-xs 
  width: 2%;


.col-sm 
  width: 10%;


.col-md 
  width: 20%;

<tbody cdkDropList (cdkDropListDropped)="onDrop($event)">
  <tr *ngFor="let user of users" cdkDrag cdkDragLockAxis="y">
    <th class="col-xs">
      <div class="drag-handle">
        <ng-container [ngTemplateOutlet]="dragHandleTmpl"> </ng-container>

      </div>
    </th>
    <td class="col-md"></td>
    <td class="col-md"></td>
    <td class="col-md"></td>
    <td class="col-md"></td>
  </tr>
</tbody>

这是最终结果

【讨论】:

以上是关于使用角材料的拖放重新排列垫表行的主要内容,如果未能解决你的问题,请参考以下文章

可重复使用的角材料垫表

如何使用角材料在具有可扩展行的表中创建嵌套垫表

将按钮动态添加到垫表角材料

如何有条件地突出显示角材料表行?

无法读取未定义的属性 - cdkDropListData 拖放角材料

Coolite 中的拖放 GridPanel 行