Skip to content

Commit

Permalink
kb(Grid): Add KB for drag-and-drop in Grid hierarchy (#2696)
Browse files Browse the repository at this point in the history
* kb(Grid): Add KB for drag-and-drop in Grid hierarchy

* Update knowledge-base/grid-drag-drop-rows-hierarchy.md

Co-authored-by: Iva Stefanova Koevska-Atanasova <[email protected]>

* Update knowledge-base/grid-drag-drop-rows-hierarchy.md

* Polish list of links

---------

Co-authored-by: Iva Stefanova Koevska-Atanasova <[email protected]>
  • Loading branch information
dimodi and ikoevska authored Jan 14, 2025
1 parent 2f0b7a7 commit b5fa9c0
Show file tree
Hide file tree
Showing 3 changed files with 268 additions and 9 deletions.
9 changes: 4 additions & 5 deletions components/grid/hierarchy.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,7 @@ The following articles and sample projects can be helpful when implementing hier

## See Also

* [Live Demo: Grid Hierarchy](https://demos.telerik.com/blazor-ui/grid/hierarchy)
* [KB: Customize Hierarchy Expand Column in Blazor Grid](slug://grid-kb-customize-hierarchy-expand-column-blazor-grid)
* [Blazor Grid](slug://grid-overview)


* [Live Demo: Grid Hierarchy](https://demos.telerik.com/blazor-ui/grid/hierarchy)
* [Customize Hierarchy Expand Column in Blazor Grid](slug://grid-kb-customize-hierarchy-expand-column-blazor-grid)
* [Drag and Drop Rows in Grid Hierarchy](slug://grid-kb-drag-drop-rows-hierarchy)
* [Blazor Grid](slug://grid-overview)
7 changes: 3 additions & 4 deletions components/grid/row-drag-drop.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,14 +132,14 @@ This section contains the following examples:

### Drag and Drop a Row between Grids

When you drag and drop items from one Grid to another, the `OnRowDrop` event fires for both Grid instances, so you can update their data sources. All Grid instances must be bound to the same model type. It is also possible to [bind the Grids to different models, but they must be derived from the same interface](slug://grid-kb-drag-drop-different-models).
When you drag and drop items from one Grid to another, the `OnRowDrop` event fires for the source Grid instance and provides information about the destination Grid. Thus you can update the data sources of both Grids. The Grid instances must be bound to the same model type. It is also possible to [bind the Grids to different models, but they must be derived from the same interface](slug://grid-kb-drag-drop-different-models).

The target drop area in the Grid is the `<table>` element. Users cannot drop items in the empty space below the last table row and this includes the `NoDataTemplate` too. There are two ways to prevent possible confusion and enhance the UX:

* Do not set a Grid `Height`, so that there is no empty space below the last table row.
* Define a [`NoDataTemplate`](slug://grid-templates-no-data), which fills the Grid data area.

The following example demonstrates both these options:
The following example demonstrates both these options. You can also check how to [drag and drop rows in a Grid hierarchy](slug://grid-kb-drag-drop-rows-hierarchy).

>caption Drag and drop items between Grids
Expand Down Expand Up @@ -1769,7 +1769,6 @@ List on known limitations for the Grid Drag and Drop features:
## See Also

* [Live Demo: Grid Drag and Drop](https://demos.telerik.com/blazor-ui/grid/drag-drop)
* [Drag and Drop Rows in Grid Hierarchy](slug://grid-kb-drag-drop-rows-hierarchy)
* [Drag and Drop between Different Parent Components](slug://grid-kb-drag-drop-in-different-components)
* [Grid API Reference](/blazor-ui/api/Telerik.Blazor.Components.TelerikGrid-1)
* [Blazor Grid](slug://grid-overview)

261 changes: 261 additions & 0 deletions knowledge-base/grid-drag-drop-rows-hierarchy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
---
title: Drag and Drop Grid Rows in Hierarchy
description: Learn how to implement and set up drag-and-drop in hierarchical Blazor Grid scenarios. Enable or disable dragging and dropping in specific Grid instances in the hierarchy.
type: how-to
page_title: How to Drag and Drop Grid Rows in Hierarchy
slug: grid-kb-drag-drop-rows-hierarchy
tags: blazor, grid, hierarchy, drag and drop
ticketid: 1675157
res_type: kb
---

## Environment

<table>
<tbody>
<tr>
<td>Product</td>
<td>
Grid for Blazor
</td>
</tr>
</tbody>
</table>

## Description

This KB answers the following questions:

* How to configure drag-and-drop in a hierarchy of Telerik Grids for Blazor?
* How to drag detail rows from a child Grid and drop them on the master (parent) Grid?
* How to prevent users from dragging and dropping master Grid rows to detail (child) Grids?

## Solution

1. Configure the [Grid hierarchy](slug://components/grid/features/hierarchy) with a `<DetailTemplate>`.
1. [Set `RowDraggable="true"` and handle the `OnRowDrop` event](slug://grid-drag-drop-overview) for the master or detail Grids.
1. [Set unique `@ref` attributes to all detail Grid instances](slug://common-kb-dynamic-refs).
1. [Set unique `@key` attributes to all detail Grid instances](slug://grid-kb-using-components-in-templates).
1. (optional) Disable dragging from certain Grids. Use custom CSS to hide specific drag columns. The example below shows how to do this separately for each Grid instance in the hierarchy.
1. (optional) Disable dropping to certain Grid instances. Use logic in the `OnRowDrop` event handlers. The example below prevents dragging and dropping of master rows to the detail Grids.

>caption Drag and drop rows in Grid hierarchy
````RAZOR
<TelerikGrid @ref="@MasterGridRef"
Data="@MasterGridData"
TItem="@GridModel"
Class="@( MasterGridDrag ? string.Empty : "no-drag-column" )"
RowDraggable="true"
OnRowDrop="@OnMasterGridDrop"
OnStateInit="@OnMasterGridInit">
<GridSettings>
<GridRowDraggableSettings DragClueField="@nameof(GridModel.Text)" />
</GridSettings>
<GridToolBarTemplate>
<label class="grid-label"><TelerikCheckBox @bind-Value="@MasterGridDrag" /> Allow Dragging</label>
<span class="k-separator"></span>
<label class="grid-label"><TelerikCheckBox @bind-Value="@MasterGridDrop" /> Allow Dropping</label>
</GridToolBarTemplate>
<GridColumns>
<GridColumn Field="@(nameof(GridModel.Id))" Width="120px" />
<GridColumn Field="@(nameof(GridModel.ParentId))" Width="120px" />
<GridColumn Field="@(nameof(GridModel.Text))" />
</GridColumns>
<DetailTemplate>
@{
var masterItem = (GridModel)context;
if (!DetailGridConfig.ContainsKey(masterItem.Id))
{
DetailGridConfig.Add(masterItem.Id, new() { GridRef = new TelerikGrid<GridModel>() });
}
}
<TelerikGrid @key="@( $"grid-detail-key-{masterItem.Id}" )"
@ref="@DetailGridConfig[masterItem.Id].GridRef"
Data="@DetailGridData.Where(x => x.ParentId == masterItem.Id)"
TItem="@GridModel"
Class="@( DetailGridConfig[masterItem.Id].AllowDrag ? string.Empty : "no-drag-column" )"
RowDraggable="true"
OnRowDrop="@OnDetailGridDrop">
<GridSettings>
<GridRowDraggableSettings DragClueField="@nameof(GridModel.Text)"></GridRowDraggableSettings>
</GridSettings>
<GridToolBarTemplate>
<label class="grid-label">
<TelerikCheckBox Value="@DetailGridConfig[masterItem.Id].AllowDrag"
ValueChanged="@( (bool newValue) => DetailGridDragChanged(newValue, masterItem.Id) )" />
Allow Dragging
</label>
<span class="k-separator"></span>
<label class="grid-label">
<TelerikCheckBox Value="@DetailGridConfig[masterItem.Id].AllowDrop"
ValueChanged="@( (bool newValue) => DetailGridDropChanged(newValue, masterItem.Id) )" />
Allow Dropping
</label>
</GridToolBarTemplate>
<GridColumns>
<GridColumn Field="@(nameof(GridModel.Id))" Width="120px" />
<GridColumn Field="@(nameof(GridModel.ParentId))" Width="120px" />
<GridColumn Field="@(nameof(GridModel.Text))" />
</GridColumns>
</TelerikGrid>
</DetailTemplate>
</TelerikGrid>
<style>
.grid-label {
display: inline-flex;
gap: .3em;
}
/* master header area */
.no-drag-column > div > .k-grid-header .k-drag-col {
width: 0;
}
.no-drag-column > div > .k-grid-header .k-drag-cell + th {
border-left-width: 0;
}
.no-drag-column > div > .k-grid-header .k-drag-cell * {
display: none;
}
/* detail data area */
.no-drag-column > div > .k-grid-container > .k-grid-content > div > div > table > colgroup > .k-drag-col {
width: 0;
}
.no-drag-column > div > .k-grid-container > .k-grid-content > div > div > table > tbody > tr > .k-drag-cell + td,
.no-drag-column > div > .k-grid-container > .k-grid-content > div > div > table > tbody > tr > .k-hierarchy-cell {
border-left-width: 0;
}
.no-drag-column > div > .k-grid-container > .k-grid-content > div > div > table > tbody > tr > .k-drag-cell * {
display: none;
}
</style>
@code {
private TelerikGrid<GridModel>? MasterGridRef { get; set; }
private Dictionary<int, GridDragDropDescriptor> DetailGridConfig { get; set; } = new();
private bool MasterGridDrag { get; set; } = true;
private bool MasterGridDrop { get; set; } = true;
private void OnMasterGridDrop(GridRowDropEventArgs<GridModel> args)
{
if (!MasterGridDrop || args.DestinationGrid != MasterGridRef)
{
return;
}
MasterGridData.Remove(args.Item);
InsertGridItem(args);
}
private void OnDetailGridDrop(GridRowDropEventArgs<GridModel> args)
{
if (args.DestinationGrid != MasterGridRef)
{
int masterId = DetailGridConfig.First(x => x.Value.GridRef == args.DestinationGrid).Key;
if (!DetailGridConfig[masterId].AllowDrop)
{
return;
}
}
else if (!MasterGridDrop)
{
return;
}
DetailGridData.Remove(args.Item);
InsertGridItem(args);
}
private void InsertGridItem(GridRowDropEventArgs<GridModel> args)
{
List<GridModel> destinationGridData = new();
int? newParentId = null;
if (args.DestinationGrid == MasterGridRef)
{
destinationGridData = MasterGridData;
}
else
{
destinationGridData = DetailGridData;
newParentId = DetailGridConfig.First(x => x.Value.GridRef == args.DestinationGrid).Key;
}
var destinationIndex = 0;
if (args.DestinationItem != null)
{
destinationIndex = destinationGridData.IndexOf(args.DestinationItem);
if (args.DropPosition == GridRowDropPosition.After)
{
destinationIndex += 1;
}
}
foreach (GridModel item in args.Items)
{
item.ParentId = newParentId;
}
destinationGridData.InsertRange(destinationIndex, args.Items);
}
private void DetailGridDragChanged(bool newValue, int masterId)
{
DetailGridConfig[masterId].AllowDrag = newValue;
}
private void DetailGridDropChanged(bool newValue, int masterId)
{
DetailGridConfig[masterId].AllowDrop = newValue;
}
private void OnMasterGridInit(GridStateEventArgs<GridModel> args)
{
args.GridState.ExpandedItems = MasterGridData;
}
private List<GridModel> MasterGridData { get; set; } = Enumerable.Range(1, 3).Select(x => new GridModel
{
Id = x,
ParentId = null,
Text = "Text " + (x)
}).ToList();
private List<GridModel> DetailGridData { get; set; } = Enumerable.Range(1, 9).Select(x => new GridModel
{
Id = 100 + x,
ParentId = x % 3 + 1,
Text = "Text " + (100 + x)
}).ToList();
public class GridModel
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Text { get; set; } = string.Empty;
}
public class GridDragDropDescriptor
{
public TelerikGrid<GridModel>? GridRef { get; set; }
public bool AllowDrag { get; set; } = true;
public bool AllowDrop { get; set; } = true;
}
}
````

## See Also

* [Grid Hierarchy](slug://components/grid/features/hierarchy)
* [Grid Drag and Drop](slug://grid-drag-drop-overview)
* [Set `@ref` to Detail Grids](slug://common-kb-dynamic-refs)
* [Use `@key` in Grid Templates](slug://grid-kb-using-components-in-templates)

0 comments on commit b5fa9c0

Please sign in to comment.