Skip to content

Commit 353ef11

Browse files
committed
chore(TreeView): validate drop target
1 parent 3601745 commit 353ef11

File tree

1 file changed

+201
-0
lines changed

1 file changed

+201
-0
lines changed
Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
---
2+
title: Validate Drop Target in TreeView
3+
description: How to validate drop target in Telerik TreeView for Blazor and prevent drop for invalid target.
4+
type: how-to
5+
page_title: How to Validate Drop Target in TreeView
6+
slug: treeview-kb-validate-drop-target
7+
position:
8+
tags: treeview, item, node, drop target, draggable, validate, invalid, prevent drop
9+
ticketid: 1592132
10+
res_type: kb
11+
---
12+
13+
## Environment
14+
15+
<table>
16+
<tbody>
17+
<tr>
18+
<td>Product</td>
19+
<td>TreeView for Blazor</td>
20+
</tr>
21+
</tbody>
22+
</table>
23+
24+
25+
## Description
26+
27+
I have a draggable TreeView and I want to prevent the user from dropping items in specific locations or folders. How can I achieve this?
28+
29+
How to validate the drop target, so I don't allow the user to drop the file if the target is invalid?
30+
31+
## Solution
32+
33+
To validate the drop target and prevent the user from dropping on an invalid target, follow these steps:
34+
35+
1. Handle the [`OnDrag`]({%slug treeview-events%}#drag-events) event of the TreeView to validate the target based on your requirements. In the example below, we are checking it the user tries to drop an item from the **Documents** folder into the **Pictures** folder - the **Pictures** folder is not a valid target in this case.
36+
1. Raise a flag if the target is not valid.
37+
1. Change the icon in the drag clue to indicate the target is not valid. Once the [Drag Clue Template](https://feedback.telerik.com/blazor/1501043-drag-clue-template) is available, you may use it to change the rendering as needed. At the time of writing, changing the icon is only possible with CSS as per the example below.
38+
1. Include a conditional logic in your [`OnDrop`]({%slug treeview-events%}#drag-events) handler to not perform any action if the target is invalid.
39+
1. Use CSS to hide the build-in drop hint for the invalid target.
40+
41+
42+
>caption Validate TreeView drop target and prevent drop for invalid target
43+
44+
````CSHTML
45+
This TreeView does not allow the user to drop items from the Documents folder into the Pictures folder.
46+
47+
<TelerikTreeView Data="@Data"
48+
@bind-ExpandedItems="@ExpandedItems"
49+
Draggable="true"
50+
DragThrottleInterval="150"
51+
OnDrag="@OnDrag"
52+
OnDrop="@OnItemDrop">
53+
</TelerikTreeView>
54+
55+
@if (IsPointerOverInvalidTarget)
56+
{
57+
<style>
58+
.k-drag-clue .k-svg-icon svg path {
59+
d: path("M256 32c-50.3 0-96.8 16.6-134.1 44.6-17.2 12.8-32.4 28.1-45.3 45.3C48.6 159.2 32 205.7 32 256c0 123.7 100.3 224 224 224 50.3 0 96.8-16.6 134.1-44.6 17.2-12.8 32.4-28.1 45.3-45.3 28-37.4 44.6-83.8 44.6-134.1 0-123.7-100.3-224-224-224m0 384c-88.2 0-160-71.8-160-160 0-32.6 9.8-62.9 26.6-88.2l221.6 221.6C318.9 406.2 288.6 416 256 416m133.4-71.8L167.8 122.6C193.1 105.8 223.4 96 256 96c88.2 0 160 71.8 160 160 0 32.6-9.8 62.9-26.6 88.2");
60+
}
61+
62+
.k-drop-hint {
63+
display: none;
64+
}
65+
</style>
66+
}
67+
68+
@code {
69+
private TreeItem DestinationItem { get; set; }
70+
private List<TreeItem> Data { get; set; } = new List<TreeItem>();
71+
private IEnumerable<object> ExpandedItems { get; set; } = Enumerable.Empty<object>();
72+
private bool IsPointerOverInvalidTarget { get; set; }
73+
74+
private void OnDrag(TreeViewDragEventArgs args)
75+
{
76+
if (args.DestinationItem != null)
77+
{
78+
var draggedItem = args.Item as TreeItem;
79+
var destinationItem = args.DestinationItem as TreeItem;
80+
81+
if (draggedItem.ParentId == 1 && (destinationItem.ParentId == 7 || destinationItem.Id == 6 || destinationItem.Id == 7))
82+
{
83+
IsPointerOverInvalidTarget = true;
84+
}
85+
else
86+
{
87+
IsPointerOverInvalidTarget = false;
88+
}
89+
}
90+
}
91+
92+
private void OnItemDrop(TreeViewDropEventArgs args)
93+
{
94+
if (IsPointerOverInvalidTarget)
95+
{
96+
return;
97+
}
98+
else
99+
{
100+
var item = args.Item as TreeItem;
101+
var destinationItem = args.DestinationItem as TreeItem;
102+
103+
if (destinationItem != null && IsChild(item, destinationItem))
104+
{
105+
return;
106+
}
107+
108+
Data.Remove(item);
109+
110+
if (item.ParentId != null && !Data.Any(x => item.ParentId == x.ParentId))
111+
{
112+
Data.FirstOrDefault(x => x.Id == item.ParentId).HasChildren = false;
113+
}
114+
115+
if (args.DropPosition == TreeViewDropPosition.Over)
116+
{
117+
item.ParentId = destinationItem.Id;
118+
destinationItem.HasChildren = true;
119+
120+
Data.Add(item);
121+
}
122+
else
123+
{
124+
var index = Data.IndexOf(destinationItem);
125+
126+
item.ParentId = destinationItem.ParentId;
127+
128+
if (args.DropPosition == TreeViewDropPosition.After)
129+
{
130+
index++;
131+
}
132+
133+
Data.Insert(index, item);
134+
}
135+
136+
// Refresh data
137+
Data = new List<TreeItem>(Data);
138+
}
139+
}
140+
141+
private bool IsChild(TreeItem item, TreeItem destinationItem)
142+
{
143+
if (destinationItem?.ParentId == null || item == null)
144+
{
145+
return false;
146+
}
147+
else if (destinationItem.ParentId?.Equals(item.Id) == true)
148+
{
149+
return true;
150+
}
151+
152+
var parentDestinationItem = Data.FirstOrDefault(e => e.Id.Equals(destinationItem.ParentId));
153+
154+
return IsChild(item, parentDestinationItem);
155+
}
156+
157+
protected override void OnInitialized()
158+
{
159+
LoadData();
160+
161+
base.OnInitialized();
162+
}
163+
164+
165+
private void LoadData()
166+
{
167+
Data = new List<TreeItem>()
168+
{
169+
new TreeItem(1, null, "Documents", SvgIcon.Folder, true),
170+
new TreeItem(2, 1, "report.xlsx", SvgIcon.FileExcel, false),
171+
new TreeItem(3, 1, "status.docx", SvgIcon.FileWord, false),
172+
new TreeItem(4, 1, "conferences.xlsx", SvgIcon.FileExcel, false),
173+
new TreeItem(5, 1, "performance.pdf", SvgIcon.FilePdf, false),
174+
new TreeItem(6, null, "Pictures", SvgIcon.Folder, true),
175+
new TreeItem(7, 6, "Camera Roll", SvgIcon.Folder, true),
176+
new TreeItem(8, 7, "team.png", SvgIcon.FileImage, false),
177+
new TreeItem(9, 7, "team-building.png", SvgIcon.FileImage, false),
178+
new TreeItem(10, 7, "friends.png", SvgIcon.FileImage, false),
179+
};
180+
ExpandedItems = Data.ToList();
181+
}
182+
183+
public class TreeItem
184+
{
185+
public int Id { get; set; }
186+
public int? ParentId { get; set; }
187+
public string Text { get; set; }
188+
public ISvgIcon Icon { get; set; }
189+
public bool HasChildren { get; set; }
190+
191+
public TreeItem(int id, int? parent, string text, ISvgIcon icon, bool hasChildren)
192+
{
193+
Id = id;
194+
ParentId = parent;
195+
Text = text;
196+
Icon = icon;
197+
HasChildren = hasChildren;
198+
}
199+
}
200+
}
201+
````

0 commit comments

Comments
 (0)