Row Dragging in Web Components Tree Grid
The Ignite UI for Web Components Row Dragging feature in Web Components Tree Grid is easily configurable and is used for rearranging rows within the grid by dragging and dropping them to a new position using the mouse. It is initialized on the root IgcTreeGridComponent
component and is configurable via the rowDraggable
input.
Web Components Tree Grid Row Drag Example
export class EmployeesNestedDataItem {
public constructor(init: Partial<EmployeesNestedDataItem>) {
Object.assign(this, init);
}
public ID: number;
public Age: number;
public Salary: number;
public Productivity: number;
public City: string;
public Country: string;
public Phone: string;
public HireDate: string;
public Name: string;
public Title: string;
public Employees: EmployeesNestedDataItem_EmployeesItem[];
}
export class EmployeesNestedDataItem_EmployeesItem {
public constructor(init: Partial<EmployeesNestedDataItem_EmployeesItem>) {
Object.assign(this, init);
}
public Age: number;
public Salary: number;
public Productivity: number;
public City: string;
public Country: string;
public Phone: string;
public HireDate: string;
public ID: number;
public Name: string;
public Title: string;
}
export class EmployeesNestedData extends Array<EmployeesNestedDataItem> {
public constructor(items: Array<EmployeesNestedDataItem> | number = -1) {
if (Array.isArray(items)) {
super(...items);
} else {
const newItems = [
new EmployeesNestedDataItem(
{
ID: 1,
Age: 55,
Salary: 80000,
Productivity: 90,
City: `Berlin`,
Country: `Germany`,
Phone: `609-202-505`,
HireDate: `2008-03-20`,
Name: `John Winchester`,
Title: `Development Manager`,
Employees: [
new EmployeesNestedDataItem_EmployeesItem(
{
Age: 43,
Salary: 70000,
Productivity: 80,
City: `Hamburg`,
Country: `Germany`,
Phone: `609-444-555`,
HireDate: `2011-06-03`,
ID: 3,
Name: `Michael Burke`,
Title: `Senior Software Developer`
}),
new EmployeesNestedDataItem_EmployeesItem(
{
Age: 29,
Salary: 60000,
Productivity: 80,
City: `Munich`,
Country: `Germany`,
Phone: `609-333-444`,
HireDate: `2009-06-19`,
ID: 2,
Name: `Thomas Anderson`,
Title: `Senior Software Developer`
}),
new EmployeesNestedDataItem_EmployeesItem(
{
Age: 31,
Salary: 90000,
Productivity: 80,
City: `Warasw`,
Country: `Poland`,
Phone: `609-222-205`,
HireDate: `2014-08-18`,
ID: 11,
Name: `Monica Reyes`,
Title: `Software Development Team Lead`
}),
new EmployeesNestedDataItem_EmployeesItem(
{
Age: 35,
Salary: 70000,
Productivity: 70,
City: `Koln`,
Country: `Germany`,
Phone: `609-502-525`,
HireDate: `2015-09-17`,
ID: 6,
Name: `Roland Mendel`,
Title: `Senior Software Developer`
})]
}),
new EmployeesNestedDataItem(
{
ID: 4,
Age: 42,
Salary: 90000,
Productivity: 80,
City: `Kielce`,
Country: `Poland`,
Phone: `609-202-505`,
HireDate: `2014-01-22`,
Name: `Ana Sanders`,
Title: `CEO`,
Employees: [
new EmployeesNestedDataItem_EmployeesItem(
{
Age: 44,
Salary: 80000,
Productivity: 80,
City: `Warasw`,
Country: `Poland`,
Phone: `609-202-505`,
HireDate: `2014-04-04`,
ID: 14,
Name: `Laurence Johnson`,
Title: `Director`
}),
new EmployeesNestedDataItem_EmployeesItem(
{
Age: 25,
Salary: 85000,
Productivity: 55,
City: `Paris`,
Country: `France`,
Phone: `609-202-505`,
HireDate: `2017-11-09`,
ID: 5,
Name: `Elizabeth Richards`,
Title: `Vice President`
}),
new EmployeesNestedDataItem_EmployeesItem(
{
Age: 39,
Salary: 88000,
Productivity: 88,
City: `London`,
Country: `UK`,
Phone: `609-202-505`,
HireDate: `2010-03-22`,
ID: 13,
Name: `Trevor Ashworth`,
Title: `Director`
})]
}),
new EmployeesNestedDataItem(
{
ID: 18,
Age: 49,
Salary: 77000,
Productivity: 70,
City: `Manchester`,
Country: `UK`,
Phone: `222-555-577`,
HireDate: `2014-01-22`,
Name: `Victoria Lincoln`,
Title: `Senior Accountant`,
Employees: [
new EmployeesNestedDataItem_EmployeesItem(
{
Age: 43,
Salary: 70000,
Productivity: 80,
City: `Hamburg`,
Country: `Germany`,
Phone: `609-444-555`,
HireDate: `2011-06-03`,
ID: 23,
Name: `Thomas Burke`,
Title: `Senior Accountant`
}),
new EmployeesNestedDataItem_EmployeesItem(
{
Age: 29,
Salary: 60000,
Productivity: 80,
City: `Munich`,
Country: `Germany`,
Phone: `609-333-444`,
HireDate: `2009-06-19`,
ID: 22,
Name: `Michael Anderson`,
Title: `Junior Accountant`
}),
new EmployeesNestedDataItem_EmployeesItem(
{
Age: 31,
Salary: 90000,
Productivity: 80,
City: `Warasw`,
Country: `Poland`,
Phone: `609-222-205`,
HireDate: `2014-08-18`,
ID: 21,
Name: `Roland Reyes`,
Title: `Accountant Team Lead`
}),
new EmployeesNestedDataItem_EmployeesItem(
{
Age: 35,
Salary: 70000,
Productivity: 70,
City: `Koln`,
Country: `Germany`,
Phone: `609-502-525`,
HireDate: `2015-09-17`,
ID: 24,
Name: `Monica Mendel`,
Title: `Senior Software Developer`
})]
}),
new EmployeesNestedDataItem(
{
ID: 10,
Age: 61,
Salary: 85000,
Productivity: 890,
City: `Lyon`,
Country: `France`,
Phone: `259-266-887`,
HireDate: `2010-01-01`,
Name: `Yang Wang`,
Title: `Localization Developer`,
Employees: [
new EmployeesNestedDataItem_EmployeesItem(
{
Age: 31,
Salary: 90000,
Productivity: 80,
City: `Warasw`,
Country: `Poland`,
Phone: `609-222-205`,
HireDate: `2014-08-18`,
ID: 11,
Name: `Monica Reyes`,
Title: `Software Development Team Lead`
}),
new EmployeesNestedDataItem_EmployeesItem(
{
Age: 35,
Salary: 70000,
Productivity: 70,
City: `Koln`,
Country: `Germany`,
Phone: `609-502-525`,
HireDate: `2015-09-17`,
ID: 6,
Name: `Roland Mendel`,
Title: `Senior Software Developer`
})]
}),
new EmployeesNestedDataItem(
{
ID: 35,
Age: 35,
Salary: 75000,
Productivity: 75,
City: `Warasw`,
Country: `Poland`,
Phone: `688-244-844`,
HireDate: `2014-01-22`,
Name: `Janine Munoz`,
Title: `HR`,
Employees: [
new EmployeesNestedDataItem_EmployeesItem(
{
Age: 43,
Salary: 70000,
Productivity: 80,
City: `Hamburg`,
Country: `Germany`,
Phone: `609-444-555`,
HireDate: `2011-06-03`,
ID: 3,
Name: `Michael Burke`,
Title: `Senior Software Developer`
}),
new EmployeesNestedDataItem_EmployeesItem(
{
Age: 31,
Salary: 90000,
Productivity: 80,
City: `Warasw`,
Country: `Poland`,
Phone: `609-222-205`,
HireDate: `2014-08-18`,
ID: 11,
Name: `Monica Reyes`,
Title: `Software Development Team Lead`
})]
}),
new EmployeesNestedDataItem(
{
ID: 10,
Age: 49,
Salary: 95000,
Productivity: 80,
City: `Krakow`,
Country: `Poland`,
Phone: `677-266-555`,
HireDate: `2010-01-01`,
Name: `Yang Wang`,
Title: `Sales Manager`,
Employees: [
new EmployeesNestedDataItem_EmployeesItem(
{
Age: 29,
Salary: 60000,
Productivity: 80,
City: `Munich`,
Country: `Germany`,
Phone: `609-333-444`,
HireDate: `2009-06-19`,
ID: 2,
Name: `Thomas Anderson`,
Title: `Senior Software Developer`
}),
new EmployeesNestedDataItem_EmployeesItem(
{
Age: 35,
Salary: 70000,
Productivity: 70,
City: `Koln`,
Country: `Germany`,
Phone: `609-502-525`,
HireDate: `2015-09-17`,
ID: 6,
Name: `Roland Mendel`,
Title: `Senior Software Developer`
})]
}),
];
super(...(newItems.slice(0, items)));
}
}
}
tsimport { IgcPropertyEditorPanelModule } from 'igniteui-webcomponents-layouts';
import 'igniteui-webcomponents-grids/grids/combined';
import { ComponentRenderer, PropertyEditorPanelDescriptionModule, WebTreeGridDescriptionModule, WebPaginatorDescriptionModule } from 'igniteui-webcomponents-core';
import { IgcTreeGridComponent, IgcGridToolbarTitleComponent } from 'igniteui-webcomponents-grids/grids';
import { EmployeesNestedDataItem, EmployeesNestedDataItem_EmployeesItem, EmployeesNestedData } from './EmployeesNestedData';
import "igniteui-webcomponents-grids/grids/themes/light/bootstrap.css";
import { ModuleManager } from 'igniteui-webcomponents-core';
import "./index.css";
ModuleManager.register(
IgcPropertyEditorPanelModule
);
export class Sample {
private treeGrid: IgcTreeGridComponent
private treeGrid2: IgcTreeGridComponent
private employees: IgcGridToolbarTitleComponent
private employeesData:EmployeesNestedData;
private _bind: () => void;
constructor() {
var treeGrid = this.treeGrid = document.getElementById('treeGrid') as IgcTreeGridComponent;
var treeGrid2 = this.treeGrid2 = document.getElementById('treeGrid2') as IgcTreeGridComponent;
var employees = this.employees = document.getElementById('Employees') as IgcGridToolbarTitleComponent;
var employeesData = new EmployeesNestedData();
this._bind = () => {
treeGrid.data = this.employeesNestedData;
treeGrid2.data = [];
treeGrid2.emptyGridMessage = "Drag and Drop a row from the left grid to this grid";
treeGrid.addEventListener("rowDragEnd", this.onGridRowDragEnd.bind(this));
}
this._bind();
}
public addRowAndChildren(row:EmployeesNestedDataItem, newData:any[]) {
if(newData.includes(row)){
return;
}
else if(newData.length>0 && row.Employees){
for(let i= row.Employees.length;i>=0;i--){
if(newData.includes(row.Employees[i])){
let index = newData.findIndex(element => element.ID === row.Employees[i].ID);
if (index > -1) {
newData.splice(index, 1);
}
}
}
}
for (let record of newData) {
if (record.Employees && record.Employees.includes(row)) {
return;
}
}
newData.push(row);
}
public onGridRowDragEnd(args: any): void {
const ghostElement = args.detail.dragDirective.ghostElement;
if (ghostElement != null) {
const dragElementPos = ghostElement.getBoundingClientRect();
const gridPosition = this.treeGrid2.getBoundingClientRect();
const withinXBounds = dragElementPos.x >= gridPosition.x && dragElementPos.x <= gridPosition.x + gridPosition.width;
const withinYBounds = dragElementPos.y >= gridPosition.y && dragElementPos.y <= gridPosition.y + gridPosition.height;
if (withinXBounds && withinYBounds) {
const newData = [...this.treeGrid2.data];
const draggedRowData = args.detail.dragData.data;
this.addRowAndChildren(draggedRowData, newData);
this.treeGrid2.data = newData;
}
}
}
private _employeesNestedData: EmployeesNestedData = null;
public get employeesNestedData(): EmployeesNestedData {
if (this._employeesNestedData == null)
{
this._employeesNestedData = new EmployeesNestedData();
}
return this._employeesNestedData;
}
private _componentRenderer: ComponentRenderer = null;
public get renderer(): ComponentRenderer {
if (this._componentRenderer == null) {
this._componentRenderer = new ComponentRenderer();
var context = this._componentRenderer.context;
PropertyEditorPanelDescriptionModule.register(context);
WebTreeGridDescriptionModule.register(context);
WebPaginatorDescriptionModule.register(context);
}
return this._componentRenderer;
}
}
new Sample();
ts<!DOCTYPE html>
<html>
<head>
<title>Sample | Ignite UI | Web Components | infragistics</title>
<meta charset="UTF-8" />
<link rel="shortcut icon" href="https://static.infragistics.com/xplatform/images/browsers/wc.png" >
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Kanit&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Titillium Web" />
<link rel="stylesheet" href="https://static.infragistics.com/xplatform/css/samples/shared.v8.css" />
<link rel="stylesheet" href="/src/index.css" type="text/css" />
</head>
<body>
<div id="root">
<div class="container sample ig-typography">
<div class="container horizontal">
<div class="container vertical" style="padding: 0.5rem;">
<igc-tree-grid
auto-generate="false"
name="treeGrid"
id="treeGrid"
child-data-key="Employees"
row-draggable="true"
>
<igc-column
field="Name"
header="Name"
data-type="string"
sortable="true"
editable="true"
resizable="true"
>
</igc-column>
<igc-column
field="HireDate"
header="Hire Date"
data-type="date"
sortable="true"
editable="true"
resizable="true">
</igc-column>
<igc-column
field="Age"
header="Age"
data-type="number"
sortable="true"
editable="true"
resizable="true">
</igc-column>
</igc-tree-grid>
</div>
<div class="container vertical" style="padding: 0.5rem;">
<igc-tree-grid
auto-generate="false"
name="treeGrid2"
id="treeGrid2"
child-data-key="Employees"
>
<igc-column
field="Name"
header="Name"
data-type="string"
sortable="true"
editable="true"
resizable="true"
>
</igc-column>
<igc-column
field="HireDate"
header="Hire Date"
data-type="date"
sortable="true"
editable="true"
resizable="true">
</igc-column>
<igc-column
field="Age"
header="Age"
data-type="number"
sortable="true"
editable="true"
resizable="true">
</igc-column>
</igc-tree-grid>
</div>
</div>
</div>
</div>
<!-- This script is needed only for parcel and it will be excluded for webpack -->
<% if (false) { %><script src="src/index.ts"></script><% } %>
</body>
</html>
html/* shared styles are loaded from: */
/* https://static.infragistics.com/xplatform/css/samples */
css
Like this sample? Get access to our complete Ignite UI for Web Components toolkit and start building your own apps in minutes. Download it for free.
Configuration
In order to enable row-dragging for your IgcTreeGridComponent
, all you need to do is set the grid's rowDraggable
to true. Once this is enabled, a row-drag handle will be displayed on each row. This handle can be used to initiate row dragging. Clicking on the drag-handle and moving the cursor while holding down the button will cause the grid's RowDragStart
event to fire. Releasing the click at any time will cause RowDragEnd
event to fire.
<igc-tree-grid row-draggable="true">
</igc-tree-grid>
html
Templating the Drag Icon
The drag handle icon can be templated using the grid's dragIndicatorIconTemplate
. In the example we're building, let's change the icon from the default one (drag_indicator) to drag_handle.
To do so, we can use the DragIndicatorIcon
to pass a template inside of the igc-tree-grid
's body:
<igc-tree-grid row-draggable="true" id="grid">
</igc-tree-grid>
html
constructor() {
var grid = this.grid = document.getElementById('grid') as IgcHierarchicalGridComponent;
grid.dragIndicatorIconTemplate = this.dragIndicatorIconTemplate;
}
public dragIndicatorIconTemplate = (ctx: IgcGridEmptyTemplateContext) => {
return html`<igc-icon name="drag_handle" collection="material"></igc-icon>`;
}
ts
Application Demo
Row Reordering Demo
With the help of the grid's row drag events you can create a grid that allows you to reorder rows by dragging them.
<igc-tree-grid id="tGrid" row-draggable="true" primary-key="ID">
</igc-tree-grid>
html
constructor() {
var tGrid = this.tGrid = document.getElementById('tGrid') as IgcTreeGridComponent;
tGrid.addEventListener("rowDragStart", this.webTreeGridReorderRowStartHandler);
tGrid.addEventListener("rowDragEnd", this.webTreeGridReorderRowHandler);
}
ts
Make sure that there is a primaryKey specified for the grid! The logic needs an unique identifier for the rows so they can be properly reordered.
Once rowDraggable
is enabled and a drop zone has been defined, you need to implement a simple handler for the drop event. When a row is dragged, check the following:
- Is the row expanded? If so, collapse it.
- Was the row dropped inside of the grid?
- If so, on which other row was the dragged row dropped?
- Once you've found the target row, swap the records' places in the
data
array - Was the row initially selected? If so, mark it as selected.
Below, you can see this implemented:
public webTreeGridReorderRowStartHandler(args: CustomEvent<IgcRowDragStartEventArgs){
const draggedRow = args.detail.dragElement;
const grid = this.treeGrid;
const row = grid.getRowByIndex(draggedRow.getAttribute('data-rowindex'));
if(row.expanded){
row.expanded = false;
}
}
public webTreeGridReorderRowHandler(args: CustomEvent<IgcRowDragEndEventArgs>): void {
const ghostElement = args.detail.dragDirective.ghostElement;
const dragElementPos = ghostElement.getBoundingClientRect();
const grid = this.treeGrid;
const rows = Array.prototype.slice.call(document.getElementsByTagName("igx-tree-grid-row"));
const currRowIndex = this.getCurrentRowIndex(rows,
{ x: dragElementPos.x, y: dragElementPos.y });
if (currRowIndex === -1) { return; }
const draggedRow = args.detail.dragData.data;
const childRows = this.findChildRows(grid.data, draggedRow);
//remove the row that was dragged and place it onto its new location
grid.deleteRow(args.detail.dragData.key);
grid.data.splice(currRowIndex, 0, args.detail.dragData.data);
// reinsert the child rows
childRows.reverse().forEach(childRow => {
grid.data.splice(currRowIndex + 1, 0, childRow);
});
}
private findChildRows(rows: any[], parent: any): any[] {
const childRows: any[] = [];
rows.forEach(row => {
if (row.ParentID === parent.ID) {
childRows.push(row);
// Recursively find children of current row
const grandchildren = this.findChildRows(rows, row);
childRows.push(...grandchildren);
}
});
return childRows;
}
public getCurrentRowIndex(rowList: any[], cursorPosition: any) {
for (const row of rowList) {
const rowRect = row.getBoundingClientRect();
if (cursorPosition.y > rowRect.top + window.scrollY && cursorPosition.y < rowRect.bottom + window.scrollY &&
cursorPosition.x > rowRect.left + window.scrollX && cursorPosition.x < rowRect.right + window.scrollX) {
// return the index of the targeted row
return parseInt(row.attributes["data-rowindex"].value);
}
}
return -1;
}
ts
With these few easy steps, you've configured a grid that allows reordering rows via drag/drop! You can see the above code in action in the following demo.
Notice that we also have row selection enabled and we preserve the selection when dropping the dragged row.
export class EmployeesNestedTreeDataItem {
public constructor(init: Partial<EmployeesNestedTreeDataItem>) {
Object.assign(this, init);
}
public Age: number;
public HireDate: string;
public ID: number;
public Name: string;
public Phone: string;
public OnPTO: boolean;
public ParentID: number;
public Title: string;
}
export class EmployeesNestedTreeData extends Array<EmployeesNestedTreeDataItem> {
public constructor(items: Array<EmployeesNestedTreeDataItem> | number = -1) {
if (Array.isArray(items)) {
super(...items);
} else {
const newItems = [
new EmployeesNestedTreeDataItem(
{
Age: 55,
HireDate: `2008-03-20`,
ID: 1,
Name: `Johnathan Winchester`,
Phone: `0251-031259`,
OnPTO: false,
ParentID: -1,
Title: `Development Manager`
}),
new EmployeesNestedTreeDataItem(
{
Age: 42,
HireDate: `2014-01-22`,
ID: 4,
Name: `Ana Sanders`,
Phone: `(21) 555-0091`,
OnPTO: true,
ParentID: -1,
Title: `CEO`
}),
new EmployeesNestedTreeDataItem(
{
Age: 49,
HireDate: `2014-01-22`,
ID: 18,
Name: `Victoria Lincoln`,
Phone: `(071) 23 67 22 20`,
OnPTO: true,
ParentID: -1,
Title: `Accounting Manager`
}),
new EmployeesNestedTreeDataItem(
{
Age: 61,
HireDate: `2010-01-01`,
ID: 10,
Name: `Yang Wang`,
Phone: `(21) 555-0091`,
OnPTO: false,
ParentID: -1,
Title: `Localization Manager`
}),
new EmployeesNestedTreeDataItem(
{
Age: 43,
HireDate: `2011-06-03`,
ID: 3,
Name: `Michael Burke`,
Phone: `0452-076545`,
OnPTO: true,
ParentID: 1,
Title: `Senior Software Developer`
}),
new EmployeesNestedTreeDataItem(
{
Age: 29,
HireDate: `2009-06-19`,
ID: 2,
Name: `Thomas Anderson`,
Phone: `(14) 555-8122`,
OnPTO: false,
ParentID: 1,
Title: `Senior Software Developer`
}),
new EmployeesNestedTreeDataItem(
{
Age: 31,
HireDate: `2014-08-18`,
ID: 11,
Name: `Monica Reyes`,
Phone: `7675-3425`,
OnPTO: false,
ParentID: 1,
Title: `Software Development Team Lead`
}),
new EmployeesNestedTreeDataItem(
{
Age: 35,
HireDate: `2015-09-17`,
ID: 6,
Name: `Roland Mendel`,
Phone: `(505) 555-5939`,
OnPTO: false,
ParentID: 11,
Title: `Senior Software Developer`
}),
new EmployeesNestedTreeDataItem(
{
Age: 44,
HireDate: `2009-10-11`,
ID: 12,
Name: `Sven Cooper`,
Phone: `0695-34 67 21`,
OnPTO: true,
ParentID: 11,
Title: `Senior Software Developer`
}),
new EmployeesNestedTreeDataItem(
{
Age: 44,
HireDate: `2014-04-04`,
ID: 14,
Name: `Laurence Johnson`,
Phone: `981-443655`,
OnPTO: false,
ParentID: 4,
Title: `Director`
}),
new EmployeesNestedTreeDataItem(
{
Age: 25,
HireDate: `2017-11-09`,
ID: 5,
Name: `Elizabeth Richards`,
Phone: `(2) 283-2951`,
OnPTO: true,
ParentID: 4,
Title: `Vice President`
}),
new EmployeesNestedTreeDataItem(
{
Age: 39,
HireDate: `2010-03-22`,
ID: 13,
Name: `Trevor Ashworth`,
Phone: `981-443655`,
OnPTO: true,
ParentID: 5,
Title: `Director`
}),
new EmployeesNestedTreeDataItem(
{
Age: 44,
HireDate: `2014-04-04`,
ID: 17,
Name: `Antonio Moreno`,
Phone: `(505) 555-5939`,
OnPTO: false,
ParentID: 18,
Title: `Senior Accountant`
}),
new EmployeesNestedTreeDataItem(
{
Age: 50,
HireDate: `2007-11-18`,
ID: 7,
Name: `Pedro Rodriguez`,
Phone: `035-640230`,
OnPTO: false,
ParentID: 10,
Title: `Senior Localization Developer`
}),
new EmployeesNestedTreeDataItem(
{
Age: 27,
HireDate: `2016-02-19`,
ID: 8,
Name: `Casey Harper`,
Phone: `0342-023176`,
OnPTO: true,
ParentID: 10,
Title: `Senior Localization`
}),
new EmployeesNestedTreeDataItem(
{
Age: 25,
HireDate: `2017-11-09`,
ID: 15,
Name: `Patricia Simpson`,
Phone: `069-0245984`,
OnPTO: false,
ParentID: 7,
Title: `Localization Intern`
}),
new EmployeesNestedTreeDataItem(
{
Age: 39,
HireDate: `2010-03-22`,
ID: 9,
Name: `Francisco Chang`,
Phone: `(91) 745 6200`,
OnPTO: false,
ParentID: 7,
Title: `Localization Intern`
}),
new EmployeesNestedTreeDataItem(
{
Age: 25,
HireDate: `2018-03-18`,
ID: 16,
Name: `Peter Lewis`,
Phone: `069-0245984`,
OnPTO: true,
ParentID: 7,
Title: `Localization Intern`
}),
];
super(...newItems.slice(0));
}
}
}
tsimport 'igniteui-webcomponents-grids/grids/combined';
import { ComponentRenderer, WebTreeGridDescriptionModule } from 'igniteui-webcomponents-core';
import { IgcTreeGridComponent } from 'igniteui-webcomponents-grids/grids';
import { EmployeesNestedTreeDataItem, EmployeesNestedTreeData } from './EmployeesNestedTreeData';
import { IgcRowDragStartEventArgs, IgcRowDragEndEventArgs } from 'igniteui-webcomponents-grids/grids';
import "igniteui-webcomponents-grids/grids/themes/light/bootstrap.css";
import "./index.css";
export class Sample {
private treeGrid: IgcTreeGridComponent
private _bind: () => void;
constructor() {
var treeGrid = this.treeGrid = document.getElementById('treeGrid') as IgcTreeGridComponent;
this.webTreeGridReorderRowStartHandler = this.webTreeGridReorderRowStartHandler.bind(this);
this.webTreeGridReorderRowHandler = this.webTreeGridReorderRowHandler.bind(this);
this._bind = () => {
treeGrid.data = this.employeesNestedTreeData;
treeGrid.addEventListener("rowDragStart", this.webTreeGridReorderRowStartHandler);
treeGrid.addEventListener("rowDragEnd", this.webTreeGridReorderRowHandler);
}
this._bind();
}
private _employeesNestedTreeData: EmployeesNestedTreeData = null;
public get employeesNestedTreeData(): EmployeesNestedTreeData {
if (this._employeesNestedTreeData == null)
{
this._employeesNestedTreeData = new EmployeesNestedTreeData();
}
return this._employeesNestedTreeData;
}
private _componentRenderer: ComponentRenderer = null;
public get renderer(): ComponentRenderer {
if (this._componentRenderer == null) {
this._componentRenderer = new ComponentRenderer();
var context = this._componentRenderer.context;
WebTreeGridDescriptionModule.register(context);
}
return this._componentRenderer;
}
public webTreeGridReorderRowStartHandler(args: CustomEvent<IgcRowDragStartEventArgs>){
const draggedRow = args.detail.dragData;
if(draggedRow.expanded){
draggedRow.expanded = false;
}
}
public webTreeGridReorderRowHandler(args: CustomEvent<IgcRowDragEndEventArgs>): void {
const ghostElement = args.detail.dragDirective.ghostElement;
const dragElementPos = ghostElement.getBoundingClientRect();
const grid = this.treeGrid;
const rows = Array.prototype.slice.call(document.getElementsByTagName("igx-tree-grid-row"));
const currRowIndex = this.getCurrentRowIndex(rows,
{ x: dragElementPos.x, y: dragElementPos.y });
if (currRowIndex === -1) { return; }
const draggedRow = args.detail.dragData.data;
const childRows = this.findChildRows(grid.data, draggedRow);
//remove the row that was dragged and place it onto its new location
grid.deleteRow(args.detail.dragData.key);
grid.data.splice(currRowIndex, 0, args.detail.dragData.data);
// reinsert the child rows
childRows.reverse().forEach(childRow => {
grid.data.splice(currRowIndex + 1, 0, childRow);
});
}
private findChildRows(rows: any[], parent: any): any[] {
const childRows: any[] = [];
rows.forEach(row => {
if (row.ParentID === parent.ID) {
childRows.push(row);
// Recursively find children of current row
const grandchildren = this.findChildRows(rows, row);
childRows.push(...grandchildren);
}
});
return childRows;
}
public getCurrentRowIndex(rowList: any[], cursorPosition: any) {
for (const row of rowList) {
const rowRect = row.getBoundingClientRect();
if (cursorPosition.y > rowRect.top + window.scrollY && cursorPosition.y < rowRect.bottom + window.scrollY &&
cursorPosition.x > rowRect.left + window.scrollX && cursorPosition.x < rowRect.right + window.scrollX) {
// return the index of the targeted row
return parseInt(row.attributes["data-rowindex"].value);
}
}
return -1;
}
}
new Sample();
ts<!DOCTYPE html>
<html>
<head>
<title>Sample | Ignite UI | Web Components | infragistics</title>
<meta charset="UTF-8" />
<link rel="shortcut icon" href="https://static.infragistics.com/xplatform/images/browsers/wc.png" >
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Kanit&display=swap" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Titillium Web" />
<link rel="stylesheet" href="https://static.infragistics.com/xplatform/css/samples/shared.v8.css" />
<link rel="stylesheet" href="/src/index.css" type="text/css" />
</head>
<body>
<div id="root">
<div class="container sample ig-typography">
<div class="container fill">
<igc-tree-grid
auto-generate="false"
name="treeGrid"
id="treeGrid"
id="treeGrid"
primary-key="ID"
foreign-key="ParentID"
row-draggable="true">
<igc-column
field="Name"
header="Full Name"
data-type="string"
resizable="true"
sortable="true"
filterable="true"
editable="true">
</igc-column>
<igc-column
field="Age"
data-type="number"
resizable="false"
sortable="false"
filterable="false"
editable="true">
</igc-column>
<igc-column
field="Title"
data-type="string"
resizable="true"
sortable="true"
filterable="true"
editable="true">
</igc-column>
<igc-column
field="HireDate"
header="Hire Date"
data-type="date"
resizable="true"
sortable="true"
filterable="true"
editable="true">
</igc-column>
</igc-tree-grid>
</div>
</div>
</div>
<!-- This script is needed only for parcel and it will be excluded for webpack -->
<% if (false) { %><script src="src/index.ts"></script><% } %>
</body>
</html>
html/* shared styles are loaded from: */
/* https://static.infragistics.com/xplatform/css/samples */
css
Limitations
Currently, there are no known limitations for the rowDraggable
.
API References
rowDraggable
RowDragStart
RowDragEnd
IgcTreeGridComponent
Additional Resources
Our community is active and always welcoming to new ideas.