The Ignite UI for Blazor Row Dragging feature in Blazor 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 IgbTreeGrid component and is configurable via the RowDraggable input.
Blazor Tree Grid Row Drag Example
EXAMPLE
MODULES
DATA
RAZOR
JS
CSS
using System;
using System.Net.Http;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Text;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using IgniteUI.Blazor.Controls; // for registering Ignite UI modulesnamespaceInfragistics.Samples
{
publicclassProgram
{
publicstaticasync Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
// registering Ignite UI modules
builder.Services.AddIgniteUIBlazor(
typeof(IgbInputModule),
typeof(IgbPropertyEditorPanelModule),
typeof(IgbTreeGridModule),
typeof(IgbPaginatorModule)
);
await builder.Build().RunAsync();
}
}
}cs
using System;
using System.Collections.Generic;
publicclassEmployeesNestedDataItem
{
publicdouble ID { get; set; }
publicdouble Age { get; set; }
publicdouble Salary { get; set; }
publicdouble Productivity { get; set; }
publicstring City { get; set; }
publicstring Country { get; set; }
publicstring Phone { get; set; }
publicstring HireDate { get; set; }
publicstring Name { get; set; }
publicstring Title { get; set; }
public List<EmployeesNestedDataItem_EmployeesItem> Employees { get; set; }
}
publicclassEmployeesNestedDataItem_EmployeesItem
{
publicdouble Age { get; set; }
publicdouble Salary { get; set; }
publicdouble Productivity { get; set; }
publicstring City { get; set; }
publicstring Country { get; set; }
publicstring Phone { get; set; }
publicstring HireDate { get; set; }
publicdouble ID { get; set; }
publicstring Name { get; set; }
publicstring Title { get; set; }
}
publicclassEmployeesNestedData
: List<EmployeesNestedDataItem>
{
publicEmployeesNestedData()
{
this.Add(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 List<EmployeesNestedDataItem_EmployeesItem>()
{
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"
}}
});
this.Add(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 List<EmployeesNestedDataItem_EmployeesItem>()
{
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"
}}
});
this.Add(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 List<EmployeesNestedDataItem_EmployeesItem>()
{
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"
}}
});
this.Add(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 List<EmployeesNestedDataItem_EmployeesItem>()
{
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"
}}
});
this.Add(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 List<EmployeesNestedDataItem_EmployeesItem>()
{
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"
}}
});
this.Add(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 List<EmployeesNestedDataItem_EmployeesItem>()
{
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"
}}
});
}
}cs
@using IgniteUI.Blazor.Controls<divclass="container vertical ig-typography"><divclass="container horizontal fill"><divclass="container vertical"style="padding: 0.5rem;"><IgbTreeGridAutoGenerate="false"Name="treeGrid"
@ref="treeGrid"Id="treeGrid"Data="EmployeesNestedData"ChildDataKey="Employees"RowDraggable=trueRowDragEndScript="OnTreeGridRowDragEndHandler"Width="100%"Height="100%"
><IgbColumnField="Name"Header="Name"DataType="GridColumnDataType.String"Sortable="true"Editable="true"
></IgbColumn><IgbColumnField="HireDate"Header="Hire Date"DataType="GridColumnDataType.Date"Sortable="true"
></IgbColumn><IgbColumnField="Age"Header="Age"DataType="GridColumnDataType.Number"Sortable="true"
></IgbColumn></IgbTreeGrid></div><divclass="container vertical"style="padding: 0.5rem;"><IgbTreeGridAutoGenerate="false"Name="treeGrid2"
@ref="treeGrid2"Id="treeGrid2"Data="Data2"EmptyGridMessage="Drag and Drop a row from the left grid to this grid"ChildDataKey="Employees"Width="100%"Height="100%"
><IgbColumnField="Name"Header="Name"DataType="GridColumnDataType.String"Sortable="true"Editable="true"
></IgbColumn><IgbColumnField="HireDate"Header="Hire Date"DataType="GridColumnDataType.Date"Sortable="true"
></IgbColumn><IgbColumnField="Age"Header="Age"DataType="GridColumnDataType.Number"Sortable="true"
></IgbColumn></IgbTreeGrid></div></div></div>@code {protectedoverrideasync Task OnAfterRenderAsync(bool firstRender)
{
var treeGrid = this.treeGrid;
var treeGrid2 = this.treeGrid2;
}
protectedoverridevoidOnInitialized()
{
this.Data2 = new List<EmployeesNestedDataItem_EmployeesItem>() { };
}
private IgbTreeGrid treeGrid;
private IgbTreeGrid treeGrid2;
private List<EmployeesNestedDataItem_EmployeesItem> Data2 { get; set; }
private EmployeesNestedData _employeesNestedData = null;
public EmployeesNestedData EmployeesNestedData
{
get
{
if (_employeesNestedData == null)
{
_employeesNestedData = new EmployeesNestedData();
}
return _employeesNestedData;
}
}
}razor
functionaddRowAndChildrenTreeGrid(row, newData) {
if (newData.includes(row)) {
return;
}
elseif (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);
}
functionOnTreeGridRowDragEndHandler(evt) {
const ghostElement = evt.detail.dragDirective.ghostElement;
const dragElementPos = ghostElement.getBoundingClientRect();
const gridPosition = 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 = [...treeGrid2.data];
const draggedRowData = evt.detail.dragData.data;
addRowAndChildrenTreeGrid(draggedRowData, newData);
treeGrid2.data = newData;
}
}
igRegisterScript("OnTreeGridRowDragEndHandler", OnTreeGridRowDragEndHandler, false);js
/*
CSS styles are loaded from the shared CSS file located at:
https://static.infragistics.com/xplatform/css/samples/
*/css
Configuration
In order to enable row-dragging for your IgbTreeGrid, 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.
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.
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:
//in JavaScript
igRegisterScript("WebTreeGridReorderRowStartHandler", (args) => {
const draggedRow = args.detail.dragElement;
const row = this.treeGrid.getRowByIndex(draggedRow.getAttribute('data-rowindex'));
if (row.expanded) {
row.expanded = false;
}
}, false);
igRegisterScript("WebTreeGridReorderRowHandler", (args) => {
const ghostElement = args.detail.dragDirective.ghostElement;
const dragElementPos = ghostElement.getBoundingClientRect();
const grid = document.getElementsByTagName("igc-tree-grid")[0];
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; }
// remove the row that was dragged and place it onto its new location
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);
});
}, false);
function findChildRows(rows, parent) {
const childRows = [];
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;
}
function getCurrentRowIndex(rowList, cursorPosition) {
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) {
// returntheindexofthetargetedrowreturnparseInt(row.attributes["data-rowindex"].value);
}
}
return-1;
}
razor
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.
EXAMPLE
MODULES
DATA
RAZOR
JS
CSS
using System;
using System.Net.Http;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Text;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using IgniteUI.Blazor.Controls; // for registering Ignite UI modulesnamespaceInfragistics.Samples
{
publicclassProgram
{
publicstaticasync Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
// registering Ignite UI modules
builder.Services.AddIgniteUIBlazor(
typeof(IgbInputModule),
typeof(IgbTreeGridModule)
);
await builder.Build().RunAsync();
}
}
}cs
using System;
using System.Collections.Generic;
publicclassEmployeesNestedTreeDataItem
{
publicdouble Age { get; set; }
publicstring HireDate { get; set; }
publicdouble ID { get; set; }
publicstring Name { get; set; }
publicstring Phone { get; set; }
publicbool OnPTO { get; set; }
publicdouble ParentID { get; set; }
publicstring Title { get; set; }
}
publicclassEmployeesNestedTreeData
: List<EmployeesNestedTreeDataItem>
{
publicEmployeesNestedTreeData()
{
this.Add(new EmployeesNestedTreeDataItem()
{
Age = 55,
HireDate = @"2008-03-20",
ID = 1,
Name = @"Johnathan Winchester",
Phone = @"0251-031259",
OnPTO = false,
ParentID = -1,
Title = @"Development Manager"
});
this.Add(new EmployeesNestedTreeDataItem()
{
Age = 42,
HireDate = @"2014-01-22",
ID = 4,
Name = @"Ana Sanders",
Phone = @"(21) 555-0091",
OnPTO = true,
ParentID = -1,
Title = @"CEO"
});
this.Add(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"
});
this.Add(new EmployeesNestedTreeDataItem()
{
Age = 61,
HireDate = @"2010-01-01",
ID = 10,
Name = @"Yang Wang",
Phone = @"(21) 555-0091",
OnPTO = false,
ParentID = -1,
Title = @"Localization Manager"
});
this.Add(new EmployeesNestedTreeDataItem()
{
Age = 43,
HireDate = @"2011-06-03",
ID = 3,
Name = @"Michael Burke",
Phone = @"0452-076545",
OnPTO = true,
ParentID = 1,
Title = @"Senior Software Developer"
});
this.Add(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"
});
this.Add(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"
});
this.Add(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"
});
this.Add(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"
});
this.Add(new EmployeesNestedTreeDataItem()
{
Age = 44,
HireDate = @"2014-04-04",
ID = 14,
Name = @"Laurence Johnson",
Phone = @"981-443655",
OnPTO = false,
ParentID = 4,
Title = @"Director"
});
this.Add(new EmployeesNestedTreeDataItem()
{
Age = 25,
HireDate = @"2017-11-09",
ID = 5,
Name = @"Elizabeth Richards",
Phone = @"(2) 283-2951",
OnPTO = true,
ParentID = 4,
Title = @"Vice President"
});
this.Add(new EmployeesNestedTreeDataItem()
{
Age = 39,
HireDate = @"2010-03-22",
ID = 13,
Name = @"Trevor Ashworth",
Phone = @"981-443655",
OnPTO = true,
ParentID = 5,
Title = @"Director"
});
this.Add(new EmployeesNestedTreeDataItem()
{
Age = 44,
HireDate = @"2014-04-04",
ID = 17,
Name = @"Antonio Moreno",
Phone = @"(505) 555-5939",
OnPTO = false,
ParentID = 18,
Title = @"Senior Accountant"
});
this.Add(new EmployeesNestedTreeDataItem()
{
Age = 50,
HireDate = @"2007-11-18",
ID = 7,
Name = @"Pedro Rodriguez",
Phone = @"035-640230",
OnPTO = false,
ParentID = 10,
Title = @"Senior Localization Developer"
});
this.Add(new EmployeesNestedTreeDataItem()
{
Age = 27,
HireDate = @"2016-02-19",
ID = 8,
Name = @"Casey Harper",
Phone = @"0342-023176",
OnPTO = true,
ParentID = 10,
Title = @"Senior Localization"
});
this.Add(new EmployeesNestedTreeDataItem()
{
Age = 25,
HireDate = @"2017-11-09",
ID = 15,
Name = @"Patricia Simpson",
Phone = @"069-0245984",
OnPTO = false,
ParentID = 7,
Title = @"Localization Intern"
});
this.Add(new EmployeesNestedTreeDataItem()
{
Age = 39,
HireDate = @"2010-03-22",
ID = 9,
Name = @"Francisco Chang",
Phone = @"(91) 745 6200",
OnPTO = false,
ParentID = 7,
Title = @"Localization Intern"
});
this.Add(new EmployeesNestedTreeDataItem()
{
Age = 25,
HireDate = @"2018-03-18",
ID = 16,
Name = @"Peter Lewis",
Phone = @"069-0245984",
OnPTO = true,
ParentID = 7,
Title = @"Localization Intern"
});
}
}cs