简体   繁体   中英

How to re-order Angular Material Table?

Objective: Create a table using Angular Material that can be modified using Angular Drag & Drop.

Expected Behavior : Table should re-order on drag-drop

Current Behavior : Rows are draggable, and the order of the underlying data source changes, but when the row is dropped it snaps back to its original position in the table.

See this example:

https://stackblitz.com/edit/drag-drop-reorder-mattable

How can this be fixed/implemented?

(Also, I'm not sure why it's styled so poorly in Stackblitz. Any insight there would also be appreciated)

Edit: I found a super hacky way to get the rows to render again with the correct order, but there's no way this is the way it's expected to be implemented. I just put t.renderRows() to be executed after the drop event handler. See full line below

<mat-table #t
  cdkDropList
  (cdkDropListDropped)="onListDrop($event); t.renderRows()" 
  [dataSource]="dataSource"
  class="mat-elevation-z8">
  ...
</mat-table>

EDIT 2: I've done a simple refactor to use rxjs, and the first drag-drop reorder for each element works great. But when I attempt to move an element that has already been moved once, I don't get the expected behavior. Stackblitz app has been updated.

You are encountering angular/material2 issue #14056 "cdkDropList: event.previousIndex does not update on second move". A workaround of deepcloning the datasource is detailed in the issue and it's comments.

Take a look here where I play with your demo after a small change to the console log ( console.log(`Moving item[${event.previousIndex}] "${this.items[event.previousIndex]}" to index ${event.currentIndex}`) )

I drag "Item 0" from index 0 to index 3. The item at index 0 moves to index 3. ✔️
I drag "Item 0" from index 3 to index 1. The item at index 0 moves to index 1. ✖️
I drag "Item 0" from index 3 to index 2. The item at index 0 moves to index 2. ✖️

The event.previousIndex erroneously remains the same for a row after it has been moved to a different index.

As you mentioned in your edit you do need to call renderRows() each time you modify the datasource. It is even mentioned in the Angular Material documentation here .

Renders rows based on the table's latest set of data, which was either provided directly as an input or retrieved through an Observable stream (directly or from a DataSource). Checks for differences in the data since the last diff to perform only the necessary changes (add/remove/move rows).

If the table's data source is a DataSource or Observable, this will be invoked automatically each time the provided Observable stream emits a new data array. Otherwise if your data is an array, this function will need to be called to render any changes.

What you could do to get around calling renderRows() each time, is to convert your datasource to an Observable and emit a new value in your onListDrop() function so the table updates automatically each time you drag/drop a row.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM