Hello everyone,
I'm looking for guidance on creating a dropdown tree with multiple APIs for different levels of hierarchy. Here's what I'm trying to achieve:
I have a dataset with over 100,000 data points organized into a hierarchy of five levels. Initially, I'd like to use an API to load the first two levels of the hierarchy. Then, upon selecting a node in the tree, I'd like to use additional APIs to load the hierarchy for that selected node.
I intend to implement this functionality within a Dropdown Tree component. Could someone please share their approach or any relevant resources to help me accomplish this task?
Thank you in advance for your assistance!
Best regards,
Gokala Sharma
Hi Gokala,
Greetings from Syncfusion support.
Based on the shared details, we understand that you want to initially add items to the Blazor Dropdown Tree component data source from the API service and also dynamically add items from the API call for the selected child items at your end. However, to achieve this, we have fetched data from an API using HttpClient in the Blazor application and assigned that data to the Dropdown Tree component data source. Similarly, we have added some additional items to the Child1 item based on the node selection with the help of the ValueChanging event.
Refer to the below code snippets.
[Index.razor]
|
@using Newtonsoft.Json @using Syncfusion.Blazor.Navigations @using Syncfusion.Blazor.Data
<SfDropDownTree TValue="int?" TItem="NodeResult" Placeholder="Select an employee" Width="500px" ValueChanging="ValueChanging"> <DropDownTreeField TItem="NodeResult" DataSource="TreeData" ID="ProductID" Text="ProductName" ParentID="pid" HasChildren="haschild"> </DropDownTreeField> </SfDropDownTree>
@code { … public bool addChildItems { get; set; } = true; protected override async Task OnInitializedAsync() { // Load initial data await LoadData(); } public List<NodeResult> TreeData = new List<NodeResult>(); private async Task LoadData() { // Fetch data from the API and initialize TreeData using (HttpClient client = new HttpClient()) { // Replace "YourApiUrl" with the actual URL of your API string apiUrl = https://localhost:7068/api/Nodes; // Send a GET request to the API var response = await client.GetAsync(apiUrl); // Check if the request was successful if (response.IsSuccessStatusCode) { // Read the response content as a string string data = await response.Content.ReadAsStringAsync(); // Deserialize the JSON data into a List<NodeResult> TreeData = JsonConvert.DeserializeObject<List<NodeResult>>(data); } } } public async Task ValueChanging(DdtChangeEventArgs<int?> args) { // Check if the selected node has an Id of 2 if (args.NodeData.Id == "2" && this.addChildItems) { // Fetch child items for "Child1" from the API using (HttpClient client = new HttpClient()) { string apiUrl = $https://localhost:7068/api/Nodes/{args.NodeData.Id}/children; var response = await client.GetAsync(apiUrl); if (response.IsSuccessStatusCode) { string data = await response.Content.ReadAsStringAsync(); List<NodeResult> childItems = JsonConvert.DeserializeObject<List<NodeResult>>(data); // Find the parent node in the TreeData list var parentNode = TreeData.FirstOrDefault(node => node.ProductID == 2); // Check if the parent node is found if (parentNode != null) { // Add each child item individually to the TreeData foreach (var childItem in childItems) { TreeData.Add(childItem); } // Set HasChildren to true for the parent node parentNode.haschild = true; } } } this.addChildItems = false; } } }
|
[NodesController.cs]
|
…
namespace BlazorApp1.Controllers { [Route("api/[controller]")] [ApiController] public class NodesController : ControllerBase { [HttpGet] public IEnumerable<NodeResult> Get() { List<NodeResult> localData = new List<NodeResult>() { new NodeResult { ProductID = 1, ProductName = "Parent", pid = null, haschild = true }, new NodeResult { ProductID = 2, ProductName = "Child1", pid = 1, haschild = false }, new NodeResult { ProductID = 3, ProductName = "Child2", pid = 1, haschild = true }, new NodeResult { ProductID = 4, ProductName = "Child3", pid = 1, haschild = false }, new NodeResult { ProductID = 5, ProductName = "SubChild1", pid = 3, haschild = false }, new NodeResult { ProductID = 6, ProductName = "SubChild2", pid = 3, haschild = false }, }; var data = localData.ToList(); var queryString = Request.Query; if (queryString.Keys.Contains("$filter")) { … } else { return data; } }
public class NodeResult { public int? ProductID { get; set; } public string ProductName { get; set; } public int? pid { get; set; } public bool? haschild { get; set; } }
[HttpGet("{parentId}/children")] public IEnumerable<NodeResult> GetChildren(int parentId) { // Fetch child items based on the parent ID // You can replace the logic below with your actual data retrieval logic List<NodeResult> childItems = new List<NodeResult>() { new NodeResult { ProductID = 8, ProductName = "Child1-SubChild1", pid = parentId, haschild = false }, new NodeResult { ProductID = 9, ProductName = "Child1-SubChild2", pid = parentId, haschild = true }, new NodeResult { ProductID = 10, ProductName = "Child1-SubChild2-SubChild1", pid = 9, haschild = false }, new NodeResult { ProductID = 11, ProductName = "Child1-SubChild2-SubChild2", pid = 9, haschild = false }, new NodeResult { ProductID = 12, ProductName = "Child1-SubChild2-SubChild3", pid = 9, haschild = true }, new NodeResult { ProductID = 13, ProductName = "Child1-SubChild2-SubChild3-SubChild1", pid = 12, haschild = false }, new NodeResult { ProductID = 14, ProductName = "Child1-SubChild2-SubChild3-SubChild2", pid = 12, haschild = false }, }; return childItems; } } } |
For your reference, we have attached the sample.
Sample: https://www.syncfusion.com/downloads/support/directtrac/general/ze/BlazorApp1-839899061.zip
Check out the attached sample and let us know if you need any further assistance.
Regards,
Prasanth Madhaiyan.
In my case, I am using the dropdown in the data grid component. I have tried this approch but the said event "
ValueChanging " is not getting triggered.
My case has Tvalue as the string.
Hi Gokala,
Based on the shared details, we have prepared a sample by setting the TValue as a string type for the Dropdown Tree component and rendered the SfDropDownTree component inside the Grid column edit template. While checking on our end, the ValueChanging event triggered without any issues.
For your reference, we have attached the sample and gif file.
Sample and GIF: Attached as a zip file.
Check out the attached sample, and if the issue still persists, could you please replicate the issue in the attached sample or share the replicated sample along with the video footage of the issue? Based on that, we will investigate and provide you with a prompt solution. Kindly get back to us with the requested details.
Regards,
Prasanth Madhaiyan.
Thank you, but now data is not getting populated in the existing dropdown tree.
Hi Gokala,
Based on the shared details, we have checked the mentioned scenario in the Dropdown Tree component by rendering it inside the Grid component, but we were unable to replicate the mentioned scenario at our end.
For your reference, we have attached the sample.
Sample: Attached as a zip file.
Please check out the attached sample. If the issue still persists, could you please replicate the issue in the attached sample or share the replicated sample of the issue? Based on that, we will investigate and provide you with a prompt solution. Kindly get back to us with the requested details.
Regards,
Prasanth Madhaiyan.
If you check the video dropdowntree is only constructed till subchild1, although we have data below this hierarchy, that data is not getting populated in the dropdowntree.
This gives the impression that the event is not getting triggered.
Yes, the event is getting triggered, but the API response is not added in the dropdown tree to construct the level below the selected level.
Hi Gokala,
Based on the shared video footage, you have clicked the SubChild1 node in the Dropdown Tree component at your end. However, in our first update, we mentioned, 'we have added some additional items to the Child1 item based on the node selection with the help of the ValueChanging event.' If you want to add items from the API call for the SubChild1 child item when you select this node at your end, you just need to make the following changes.
[Index.razor]
|
…
<SfGrid DataSource="@GridData" AllowPaging="true" Toolbar="@(new List<string>() { "Add", "Edit", "Delete", "Cancel", "Update" })" Height="315"> <GridEditSettings AllowAdding="true" AllowEditing="true" AllowDeleting="true" Mode="EditMode.Normal"></GridEditSettings> <GridColumns> <GridColumn Field=@nameof(NodeResult.ProductID) HeaderText="Order ID" IsPrimaryKey="true" TextAlign="TextAlign.Right" Width="120"></GridColumn> <GridColumn Field=@nameof(NodeResult.ProductName) HeaderText="Product Name" EditType="EditType.DropDownEdit" Width="150"> <EditTemplate> @{
<SfDropDownTree ID="ProductName" TValue="string?" TItem="NodeResult" Placeholder="Select an employee" Width="500px" ValueChanging="ValueChanging"> <DropDownTreeField TItem="NodeResult" DataSource="TreeData" ID="ProductID" Text="ProductName" ParentID="pid" HasChildren="haschild"> </DropDownTreeField> </SfDropDownTree> }
</EditTemplate> </GridColumn> </GridColumns> </SfGrid> @code { public class NodeResult { public string? ProductID { get; set; } public string? ProductName { get; set; } public int? pid { get; set; } public bool? haschild { get; set; } } public bool addChildItems { get; set; } = true; protected override async Task OnInitializedAsync() { // Load initial data await LoadData(); } public List<NodeResult> GridData = new List<NodeResult>(); public List<NodeResult> TreeData = new List<NodeResult>(); private async Task LoadData() { // Fetch data from the API and initialize TreeData using (HttpClient client = new HttpClient()) { // Replace "YourApiUrl" with the actual URL of your API string apiUrl = https://localhost:7068/api/Nodes;
// Send a GET request to the API var response = await client.GetAsync(apiUrl);
// Check if the request was successful if (response.IsSuccessStatusCode) { // Read the response content as a string string data = await response.Content.ReadAsStringAsync();
// Deserialize the JSON data into a List<NodeResult> TreeData = JsonConvert.DeserializeObject<List<NodeResult>>(data); } } } public async Task ValueChanging(DdtChangeEventArgs<string?> args) {
// Check if the selected node has an Id of 5 if (args.NodeData.Id == "5" && this.addChildItems) { // Fetch child items for " SubChild1" from the API using (HttpClient client = new HttpClient()) { string apiUrl = $https://localhost:7068/api/Nodes/{args.NodeData.Id}/children; var response = await client.GetAsync(apiUrl);
if (response.IsSuccessStatusCode) { string data = await response.Content.ReadAsStringAsync(); List<NodeResult> childItems = JsonConvert.DeserializeObject<List<NodeResult>>(data);
// Find the parent node in the TreeData list var parentNode = TreeData.FirstOrDefault(node => node.ProductID == "5");
// Check if the parent node is found if (parentNode != null) {
// Add each child item individually to the TreeData foreach (var childItem in childItems) { TreeData.Add(childItem); }
// Set HasChildren to true for the parent node parentNode.haschild = true; } }
} this.addChildItems = false; }
}
} |
For your reference, we have attached the sample.
Sample: Attached as a zip file.
Check out the attached sample and let us know if you need any further assistance.
Regards,
Prasanth Madhaiyan.