I am trying to achieve drag and drop functionality in angular table row but the issue is the table I have has spanned row.When I try to drag and drop the spanned row it just pick up a single row instead of whole spanned row.
I am using https://stackblitz.com/edit/angular-wudscb-kpjdfv to achieve row span in angular table.
app.component.html
<table mat-table [dataSource]="dataSource"
class="mat-elevation-z8" multiTemplateDataRows
cdkDropList
[cdkDropListData]="dataSource"
(cdkDropListDropped)="dropTable($event)">
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef> Priority </th>
<td mat-cell *matCellDef="let data;let i = dataIndex" [attr.rowspan]="getRowSpan('Priority',i)" [style.display]="getRowSpan('Priority', i) ? '' : 'none'">
{{ data.id }} </td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Name </th>
<td mat-cell *matCellDef="let data;let i = dataIndex" [attr.rowspan]="getRowSpan('Name',i)" [style.display]="getRowSpan('Name', i) ? '' : 'none'">
{{ data.name }} </td>
</ng-container>
<ng-container matColumnDef="weight">
<th mat-header-cell *matHeaderCellDef> Weight </th>
<td mat-cell *matCellDef="let data;let i = dataIndex" [attr.rowspan]="getRowSpan('Weight',i)" [style.display]="getRowSpan('Weight', i) ? '' : 'none'">
{{ data.weight }} </td>
</ng-container>
<ng-container matColumnDef="descriptions">
<th mat-header-cell *matHeaderCellDef> Descriptions </th>
<td mat-cell *matCellDef="let data"> {{ data.descriptions }} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" cdkDrag [cdkDragData]="row"></tr>
</table>
app.component.ts
import { Component , ViewChild } from '@angular/core';
import {CdkDragDrop, moveItemInArray, transferArrayItem, CdkDragHandle} from '@angular/cdk/drag-drop';
import { MatTable } from '@angular/material';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
@ViewChild('table') table: MatTable<PeriodicElement>;
dataSource = ELEMENT_DATA;
displayedColumns = ['id', 'name', 'weight', 'descriptions'];
spans = [];
tempRowId = null;
tempRowCount = null;
constructor() {
this.cacheSpan('Priority', d => d.id);
this.cacheSpan('Name', d => d.name);
this.cacheSpan('Weight', d => d.weight);
}
/**
* Evaluated and store an evaluation of the rowspan for each row.
* The key determines the column it affects, and the accessor determines the
* value that should be checked for spanning.
*/
cacheSpan(key, accessor) {
for (let i = 0; i < DATA.length;) {
let currentValue = accessor(DATA[i]);
let count = 1;
// Iterate through the remaining rows to see how many match
// the current value as retrieved through the accessor.
for (let j = i + 1; j < DATA.length; j++) {
if (currentValue != accessor(DATA[j])) {
break;
}
count++;
}
if (!this.spans[i]) {
this.spans[i] = {};
}
// Store the number of similar values that were found (the span)
// and skip i to the next unique row.
this.spans[i][key] = count;
i += count;
}
}
getRowSpan(col, index) {
return this.spans[index] && this.spans[index][col];
}
dropTable(event: CdkDragDrop<PeriodicElement[]>) {
const prevIndex = this.dataSource.findIndex((d) => d === event.item.data);
moveItemInArray(this.dataSource, prevIndex, event.currentIndex);
this.table.renderRows();
}
}
export interface PeriodicElement {
id: number;
name: string;
weight: number;
descriptions: string[];
}
const originalData = [
{ id: 1, name: 'Hydrogen', weight: 1.0079, descriptions: ['row1', 'row2'] },
{ id: 2, name: 'Helium', weight: 4.0026, descriptions: ['row1', 'row2', 'row3'] },
{ id: 3, name: 'Lithium', weight: 6.941, descriptions: ['row1', 'row2'] },
{ id: 4, name: 'Beryllium', weight: 9.0122, descriptions: ['row1', 'row2', 'row3'] },
{ id: 5, name: 'Boron', weight: 10.811, descriptions: ['row1'] },
{ id: 6, name: 'Carbon', weight: 12.0107, descriptions: ['row1', 'row2', 'row3'] },
{ id: 7, name: 'Nitrogen', weight: 14.0067, descriptions: ['row1'] },
{ id: 8, name: 'Oxygen', weight: 15.9994, descriptions: ['row1'] },
{ id: 9, name: 'Fluorine', weight: 18.9984, descriptions: ['row1', 'row2', 'row3'] },
{ id: 10, name: 'Neon', weight: 20.1797, descriptions: ['row1', 'row2', 'row3'] },
]
const DATA = originalData.reduce((current, next) => {
next.descriptions.forEach(b => {
current.push({ id: next.id, name: next.name, weight: next.weight, descriptions: b })
});
return current;
}, []);
console.log(DATA)
const ELEMENT_DATA: PeriodicElement[] = DATA;
I want the whole spanned row to be able to drag and drop to other place.