import { Component, AfterViewInit, Renderer2, NgZone, OnDestroy, ViewEncapsulation } from '@angular/core';
import { GridComponent } from '@progress/kendo-angular-grid';
import { take } from 'rxjs/operators';
import { Product } from './model';
import { sampleProducts } from './products';
import { tableRow, closest } from './utils';
@Component({
selector: 'my-app',
encapsulation: ViewEncapsulation.None,
styleUrls: ['./styles.css'],
template: `
`
})
export class AppComponent implements AfterViewInit, OnDestroy {
public firstGridData = sampleProducts.slice(0, 3);
public secondGridData = sampleProducts.slice(3, 6);
public gridList=[];
public dropIndex;
public noRecordsMsg = 'No records available yet. Please drop a row.';
public currentGridRef: GridComponent;
public targetCells: NodeListOf;
constructor(private renderer: Renderer2, public zone: NgZone) {}
public ngAfterViewInit() {
this.setDraggableRows();
}
public ngOnDestroy() {
this.destroyListeners();
}
public destroyListeners(): void {
const tableRows: Array = this.getAllRows();
tableRows.forEach((item) => {
item.removeEventListener('dragstart', () => {});
});
}
public setDraggableRows(): void {
const tableRows: Array = this.getAllRows();
tableRows.forEach((item: HTMLElement) => {
this.renderer.setAttribute(item, 'draggable', 'true');
this.addDragListeners(item);
});
}
public getAllRows(): Array {
return Array.from(document.querySelectorAll('.k-grid tr'));
}
public addDragListeners(item: HTMLElement): void {
item.addEventListener('dragstart', (e: DragEvent) => {
const rowItem: HTMLTableDataCellElement = item.querySelector('td');
// Prevents dragging Grid header row
if (rowItem === null) {
return;
}
let selectedItem: Product = sampleProducts.find((i) => i.ProductID === Number(rowItem.textContent));
let dataItem = JSON.stringify(selectedItem);
e.dataTransfer.setData('text/plain', dataItem);
});
}
// Prevents dragging header and 'no records' row.
public onDragStart(e: DragEvent, grid: GridComponent): void {
this.currentGridRef = grid;
const draggedElement: string = (e.target as HTMLElement).innerText;
if (draggedElement.includes('ID') || draggedElement === this.noRecordsMsg) {
e.preventDefault();
}
}
public onDrop(e: DragEvent, dragStartGridRef: GridComponent, droppedRowGridRef: GridComponent): void {
let data = e.dataTransfer.getData('text/plain');
let droppedItem: Product = JSON.parse(data);
// Prevent dropping row in the same Grid
if (dragStartGridRef !== this.currentGridRef) {
this.updateGridsData(droppedItem, droppedRowGridRef, dragStartGridRef);
}
// When new row is added to a table, the draggable attributes is set to that row.
this.zone.onStable.pipe(take(1)).subscribe(() => {
this.destroyListeners();
this.setDraggableRows();
});
this.removeLineIndicators();
}
public onDragOver(e: DragEvent, grid: GridComponent): void {
e.preventDefault();
if (this.targetCells) {
this.removeLineIndicators();
}
const targetEl = e.target as HTMLElement;
if (this.currentGridRef !== grid && (targetEl.tagName === 'TD' || targetEl.tagName === 'TH')) {
// Set drop line indication
this.targetCells = targetEl.parentElement.querySelectorAll('td, th');
this.targetCells.forEach((td: HTMLElement) => {
const gridData: any[] = grid.data as any[];
if (td.tagName === 'TH' && gridData.length !== 0) {
this.renderer.addClass(td, 'th-line');
this.dropIndex = 0;
} else if (td.tagName === 'TD') {
this.renderer.addClass(td, 'td-line');
this.dropIndex = closest(e.target, tableRow).rowIndex + 1;
}
});
}
}
public removeLineIndicators() {
this.targetCells.forEach((td: HTMLElement) => {
this.renderer.removeAttribute(td, 'class');
});
}
public updateGridsData(droppedItem: Product, droppedRowGridRef: GridComponent, dragStartGridRef: GridComponent): void {
const droppedRowGridData = droppedRowGridRef.data as Array;
const dragStartGridData = dragStartGridRef.data as Array;
let index: number = droppedRowGridData.findIndex((i) => i.ProductID === droppedItem.ProductID);
droppedRowGridData.splice(index, 1);
dragStartGridData.splice(this.dropIndex, 0, droppedItem);
}
}