From dc9b3cf612f36fd1d2627d6db42ce14e19f08936 Mon Sep 17 00:00:00 2001 From: Nadezhda Tacheva Date: Fri, 29 Nov 2024 13:50:08 +0200 Subject: [PATCH 1/4] chore(TreeView): add KB for drag to a custom target --- components/treeview/drag-drop.md | 1 + .../treeview-drag-to-custom-target.md | 209 ++++++++++++++++++ 2 files changed, 210 insertions(+) create mode 100644 knowledge-base/treeview-drag-to-custom-target.md diff --git a/components/treeview/drag-drop.md b/components/treeview/drag-drop.md index 78035edd98..4e12b81565 100644 --- a/components/treeview/drag-drop.md +++ b/components/treeview/drag-drop.md @@ -1352,3 +1352,4 @@ using System.Collections.ObjectModel; * [Live Demo: TreeView Drag and Drop](https://demos.telerik.com/blazor-ui/treeview/drag-drop) * [Data Binding a TreeView]({%slug components/treeview/data-binding/overview%}) * [TreeView API Reference](/blazor-ui/api/Telerik.Blazor.Components.TelerikTreeView) +* [Dragging TreeView Items to a Custom Target]({%slug treeview-kb-drag-to-custom-target%}) diff --git a/knowledge-base/treeview-drag-to-custom-target.md b/knowledge-base/treeview-drag-to-custom-target.md new file mode 100644 index 0000000000..8b27b7e952 --- /dev/null +++ b/knowledge-base/treeview-drag-to-custom-target.md @@ -0,0 +1,209 @@ +--- +title: Dragging TreeView Items to a Custom Target +description: How to support draging and reordering items inside the TreeView but also allow dragging and dropping items outside the component to a custom target +type: how-to +page_title: How to Drag TreeView Items to a Custom Target +slug: treeview-kb-drag-to-custom-target +position: +tags: +ticketid: 1592132 +res_type: kb +--- + +## Environment + + + + + + + + +
ProductTreeView for Blazor
+ +## Description + +I have a TreeView that allows dragging and reordering items inside the component. I want to also allow dragging items outside the TreeView, so the users can drop them on custom target. How to achieve that? + +## Solution + +To allow dragging outside the TreeView and dropping on a custom target, follow these steps: + +1. Handle the [`OnDragStart`]({%slug treeview-events%}#drag-events) event of the TreeView to get the item that the user started dragging. +1. Handle the [`@onpointerup`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointerup_event) event of your custom target to add the TreeView inside as needed. Based on product specifics, the TreeView internally does not use draggable events, it uses pointer events to handle the dragging. Therefore, `@ondrop` of your custom target will not fire when dragging a TreeView item in it as the component expects a subsequent pointer event. Use the `@onpointerup` instead of `@ondrop`. +1. Change the icon in the drop clue when the user drags over the custom target to indicate it is an allowed target. 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 dime of writing, changing the icon is only possible with CSS. For that purpose: + 1. Handle [`@onpointerenter`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointerenter_event) and [`@onpointerout`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointerout_event) events of the custom target to detect when the user drags the item over it. + 1. Raise and drop a flag based on the pointer position. + 1. Conditionally apply custom CSS to change the drop clue icon based on the flag. + +>caption Draggable Treeview that allows dropping items in a custom target + +````CSHTML + + + + + + +@* - Render the desired icon to get its path. *@ + +
+ + @foreach (var item in DroppedItems) + { + @item.Text +
+ } +
+ + + +@if (IsPointerOverCustomTarget && !IsItemAlreadyInCustomTarget) +{ + +} + +@code { + private TreeItem DraggedtItem { get; set; } + private List Data { get; set; } + private IEnumerable ExpandedItems { get; set; } + private List DroppedItems { get; set; } = new List(); + private bool IsPointerOverCustomTarget { get; set; } + private bool IsItemAlreadyInCustomTarget { get; set; } + + + private void OnDragStart(TreeViewDragStartEventArgs args) + { + DraggedtItem = (TreeItem)args.Item; + + IsItemAlreadyInCustomTarget = DroppedItems.Any(x => x.Id == DraggedtItem.Id); + } + + private void CustomTargetDropHandler() + { + if (DraggedtItem != null && !IsItemAlreadyInCustomTarget) + { + DroppedItems.Add(DraggedtItem); + } + } + + private void TreeViewDropHandler(TreeViewDropEventArgs args) + { + var item = args.Item as TreeItem; + var destinationItem = args.DestinationItem as TreeItem; + + if (destinationItem != null && IsChild(item, destinationItem)) + { + return; + } + + Data.Remove(item); + + if (item.Parent != null && !Data.Any(x => item.Parent == x.Parent)) + { + Data.FirstOrDefault(x => x.Id == item.Parent).HasChildren = false; + } + + if (args.DropPosition == TreeViewDropPosition.Over) + { + item.Parent = destinationItem.Id; + destinationItem.HasChildren = true; + + Data.Add(item); + } + else + { + var index = Data.IndexOf(destinationItem); + + item.Parent = destinationItem.Parent; + + if (args.DropPosition == TreeViewDropPosition.After) + { + index++; + } + + Data.Insert(index, item); + } + + // Refresh data + Data = new List(Data); + } + + private bool IsChild(TreeItem item, TreeItem destinationItem) + { + if (destinationItem?.Parent == null || item == null) + { + return false; + } + else if (destinationItem.Parent?.Equals(item.Id) == true) + { + return true; + } + + var parentDestinationItem = Data.FirstOrDefault(e => e.Id.Equals(destinationItem.Parent)); + + return IsChild(item, parentDestinationItem); + } + + protected override void OnInitialized() + { + LoadData(); + + base.OnInitialized(); + } + + private void LoadData() + { + Data = new List() + { + new TreeItem(1, null, "Documents", SvgIcon.Folder, true), + new TreeItem(2, 1, "report.xlsx", SvgIcon.FileExcel, false), + new TreeItem(3, 1, "status.docx", SvgIcon.FileWord, false), + new TreeItem(4, 1, "conferences.xlsx", SvgIcon.FileExcel, false), + new TreeItem(5, 1, "performance.pdf", SvgIcon.FilePdf, false), + new TreeItem(6, null, "Pictures", SvgIcon.Folder, true), + new TreeItem(7, 6, "Camera Roll", SvgIcon.Folder, true), + new TreeItem(8, 7, "team.png", SvgIcon.FileImage, false), + new TreeItem(9, 7, "team-building.png", SvgIcon.FileImage, false), + new TreeItem(10, 7, "friends.png", SvgIcon.FileImage, false), + }; + ExpandedItems = Data.ToList(); + } + + public class TreeItem + { + public int Id { get; set; } + public int? Parent { get; set; } + public string Text { get; set; } + public ISvgIcon Icon { get; set; } + public bool HasChildren { get; set; } + + public TreeItem(int id, int? parent, string text, ISvgIcon icon, bool hasChildren) + { + Id = id; + Parent = parent; + Text = text; + Icon = icon; + HasChildren = hasChildren; + } + } +} +```` \ No newline at end of file From 6b124bd2490dac222db4d6c882a7b970e980f8d8 Mon Sep 17 00:00:00 2001 From: Nadezhda Tacheva <73842592+ntacheva@users.noreply.github.com> Date: Fri, 29 Nov 2024 14:12:42 +0200 Subject: [PATCH 2/4] Update knowledge-base/treeview-drag-to-custom-target.md --- knowledge-base/treeview-drag-to-custom-target.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/knowledge-base/treeview-drag-to-custom-target.md b/knowledge-base/treeview-drag-to-custom-target.md index 8b27b7e952..ff87a2711b 100644 --- a/knowledge-base/treeview-drag-to-custom-target.md +++ b/knowledge-base/treeview-drag-to-custom-target.md @@ -31,7 +31,7 @@ To allow dragging outside the TreeView and dropping on a custom target, follow t 1. Handle the [`OnDragStart`]({%slug treeview-events%}#drag-events) event of the TreeView to get the item that the user started dragging. 1. Handle the [`@onpointerup`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointerup_event) event of your custom target to add the TreeView inside as needed. Based on product specifics, the TreeView internally does not use draggable events, it uses pointer events to handle the dragging. Therefore, `@ondrop` of your custom target will not fire when dragging a TreeView item in it as the component expects a subsequent pointer event. Use the `@onpointerup` instead of `@ondrop`. -1. Change the icon in the drop clue when the user drags over the custom target to indicate it is an allowed target. 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 dime of writing, changing the icon is only possible with CSS. For that purpose: +1. Change the icon in the drag clue when the user drags over the custom target to indicate it is an allowed target. 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. For that purpose: 1. Handle [`@onpointerenter`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointerenter_event) and [`@onpointerout`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointerout_event) events of the custom target to detect when the user drags the item over it. 1. Raise and drop a flag based on the pointer position. 1. Conditionally apply custom CSS to change the drop clue icon based on the flag. From 1fa5366f1f053ca04e65f97974a59bbcbcfafb16 Mon Sep 17 00:00:00 2001 From: Nadezhda Tacheva <73842592+ntacheva@users.noreply.github.com> Date: Fri, 29 Nov 2024 14:43:30 +0200 Subject: [PATCH 3/4] Update knowledge-base/treeview-drag-to-custom-target.md Co-authored-by: Dimo Dimov <961014+dimodi@users.noreply.github.com> --- knowledge-base/treeview-drag-to-custom-target.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/knowledge-base/treeview-drag-to-custom-target.md b/knowledge-base/treeview-drag-to-custom-target.md index ff87a2711b..e41b1bcb18 100644 --- a/knowledge-base/treeview-drag-to-custom-target.md +++ b/knowledge-base/treeview-drag-to-custom-target.md @@ -1,5 +1,5 @@ --- -title: Dragging TreeView Items to a Custom Target +title: Drag TreeView Items to a Custom Target description: How to support draging and reordering items inside the TreeView but also allow dragging and dropping items outside the component to a custom target type: how-to page_title: How to Drag TreeView Items to a Custom Target From 51ff24892541034ca877cc7123ebc6f2c9f9bdba Mon Sep 17 00:00:00 2001 From: Nadezhda Tacheva Date: Fri, 29 Nov 2024 14:54:30 +0200 Subject: [PATCH 4/4] chore(TreeView): address feedback --- components/treeview/drag-drop.md | 2 +- .../treeview-drag-to-custom-target.md | 35 +++++++++---------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/components/treeview/drag-drop.md b/components/treeview/drag-drop.md index 4e12b81565..ae682768a7 100644 --- a/components/treeview/drag-drop.md +++ b/components/treeview/drag-drop.md @@ -1352,4 +1352,4 @@ using System.Collections.ObjectModel; * [Live Demo: TreeView Drag and Drop](https://demos.telerik.com/blazor-ui/treeview/drag-drop) * [Data Binding a TreeView]({%slug components/treeview/data-binding/overview%}) * [TreeView API Reference](/blazor-ui/api/Telerik.Blazor.Components.TelerikTreeView) -* [Dragging TreeView Items to a Custom Target]({%slug treeview-kb-drag-to-custom-target%}) +* [Drag TreeView Items to a Custom Target]({%slug treeview-kb-drag-to-custom-target%}) diff --git a/knowledge-base/treeview-drag-to-custom-target.md b/knowledge-base/treeview-drag-to-custom-target.md index e41b1bcb18..db4dc82aa0 100644 --- a/knowledge-base/treeview-drag-to-custom-target.md +++ b/knowledge-base/treeview-drag-to-custom-target.md @@ -44,9 +44,6 @@ To allow dragging outside the TreeView and dropping on a custom target, follow t Draggable="true" OnDragStart="@OnDragStart" OnDrop="@TreeViewDropHandler"> - - - @* - Render the desired icon to get its path. *@ @@ -56,10 +53,10 @@ To allow dragging outside the TreeView and dropping on a custom target, follow t @onpointerenter="@((PointerEventArgs args) => IsPointerOverCustomTarget = true)" @onpointerout="@((PointerEventArgs args) => IsPointerOverCustomTarget = false)"> - @foreach (var item in DroppedItems) + @foreach (var item in DroppedItems) { - @item.Text -
+ @item.Text +
} @@ -83,8 +80,8 @@ To allow dragging outside the TreeView and dropping on a custom target, follow t @code { private TreeItem DraggedtItem { get; set; } - private List Data { get; set; } - private IEnumerable ExpandedItems { get; set; } + private List Data { get; set; } = new List(); + private IEnumerable ExpandedItems { get; set; } = Enumerable.Empty(); private List DroppedItems { get; set; } = new List(); private bool IsPointerOverCustomTarget { get; set; } private bool IsItemAlreadyInCustomTarget { get; set; } @@ -100,10 +97,10 @@ To allow dragging outside the TreeView and dropping on a custom target, follow t private void CustomTargetDropHandler() { if (DraggedtItem != null && !IsItemAlreadyInCustomTarget) - { + { DroppedItems.Add(DraggedtItem); } - } + } private void TreeViewDropHandler(TreeViewDropEventArgs args) { @@ -117,14 +114,14 @@ To allow dragging outside the TreeView and dropping on a custom target, follow t Data.Remove(item); - if (item.Parent != null && !Data.Any(x => item.Parent == x.Parent)) + if (item.ParentId != null && !Data.Any(x => item.ParentId == x.ParentId)) { - Data.FirstOrDefault(x => x.Id == item.Parent).HasChildren = false; + Data.FirstOrDefault(x => x.Id == item.ParentId).HasChildren = false; } if (args.DropPosition == TreeViewDropPosition.Over) { - item.Parent = destinationItem.Id; + item.ParentId = destinationItem.Id; destinationItem.HasChildren = true; Data.Add(item); @@ -133,7 +130,7 @@ To allow dragging outside the TreeView and dropping on a custom target, follow t { var index = Data.IndexOf(destinationItem); - item.Parent = destinationItem.Parent; + item.ParentId = destinationItem.ParentId; if (args.DropPosition == TreeViewDropPosition.After) { @@ -149,16 +146,16 @@ To allow dragging outside the TreeView and dropping on a custom target, follow t private bool IsChild(TreeItem item, TreeItem destinationItem) { - if (destinationItem?.Parent == null || item == null) + if (destinationItem?.ParentId == null || item == null) { return false; } - else if (destinationItem.Parent?.Equals(item.Id) == true) + else if (destinationItem.ParentId?.Equals(item.Id) == true) { return true; } - var parentDestinationItem = Data.FirstOrDefault(e => e.Id.Equals(destinationItem.Parent)); + var parentDestinationItem = Data.FirstOrDefault(e => e.Id.Equals(destinationItem.ParentId)); return IsChild(item, parentDestinationItem); } @@ -191,7 +188,7 @@ To allow dragging outside the TreeView and dropping on a custom target, follow t public class TreeItem { public int Id { get; set; } - public int? Parent { get; set; } + public int? ParentId { get; set; } public string Text { get; set; } public ISvgIcon Icon { get; set; } public bool HasChildren { get; set; } @@ -199,7 +196,7 @@ To allow dragging outside the TreeView and dropping on a custom target, follow t public TreeItem(int id, int? parent, string text, ISvgIcon icon, bool hasChildren) { Id = id; - Parent = parent; + ParentId = parent; Text = text; Icon = icon; HasChildren = hasChildren;