Set treeview hierarchy from javascript

4 posts, 0 answers
  1. Sam
    Sam avatar
    7 posts
    Member since:
    Sep 2019

    Posted 24 Oct Link to this post

    My requirements are such that on initial load, the tree is empty and a user can do a search which would then load the results into the treeview.  Once the view is loaded, the user will navigate the tree with the expand functions.  It's possible that the user searches for a result that is at an arbitrary depth in the tree (not a top-level node) so I query all nodes from the root down to the search result.  I need help figuring out how to set this hierarchy of nodes into the tree correctly.  Currently, only the top-level node displays with no expander.

     

    The object to be displayed in tree:

    public class LocationModel
     {
         public string Id { get; set; }
         public string ParentId { get; set; }
         public string Name { get; set; }
         public List<LocationModel> Children { get; set; } = new List<LocationModel>();
         public bool HasChildren => true;
     }

     

    The controller:

    public JsonResult GetLocationHierarchy(string locationId)
    {
        if (string.IsNullOrEmpty(locationId))
            return new JsonResult();
        //string id;
        var results = new List<LocationModel>();
     
        using (var ctx = _docStore.OpenSession())
        {
            // recursively step up the tree, adding each node to the list
            while (!string.IsNullOrWhiteSpace(locationId))
            {
                var thisNode = (from l in ctx.Query<Location>()
                                where l.Id.Equals(locationId)
                                select new LocationModel
                                {
                                    Id = l.Id,
                                    Name = l.FriendlyName,
                                    ParentId = l.ParentId
                                }).SingleOrDefault();
     
                if (thisNode != null)
                {
                    results.Add(thisNode);
                    locationId = thisNode.ParentId;
                }
                else
                    locationId = string.Empty;
            }
        }
                 
        // set the children on the nodes
        foreach (var node in results)
            node.Children = results.Where(x => x.ParentId == node.Id).ToList();
     
        //return only the top level node (hierachy is in place)
        return Json(results.Where(x=> x.ParentId == string.Empty).ToList(), JsonRequestBehavior.AllowGet);

     

    The tree view:

    <div id="treeview">
         <div class="demo-section k-content">
             @(Html.Kendo().TreeView()
                               .Name("treeView")
                               .LoadOnDemand(true)
                               .DataTextField("Name")
                               .Events(events => events
                                   .Select("onSelect")
                                   .Expand("onExpand")
                               )
                               .DataSource(dataSource => dataSource
                               .Model(m =>
                               {
                                   m.Id("Id");
                                   m.Field("Name", typeof(string));
                                   m.Children("Children");
                                   m.HasChildren("HasChildren");
                               })
                                 .Read(read => read
                                   .Action("GetLocationChildren", "Home", new { locationId = Model.SelectedLocation.Id })
                               )
                               )
             )
         </div>
     </div>

     

    The search button method:

    function onSearchButtonClick(e) {
            if ($("#SelectedLocation_Name").val() == "") {
                console.log("No SelectedLocation Name");
                return;
            }
             var u = '@Url.Action("GetLocationHierarchy")';
            $.post(u,
                {
                    locationId: $("#SelectedLocation_Id").val()
                },
                function (data) {
                    console.log("onSearchButtonClick returned...");
                    var treeView = $("#treeView").data("kendoTreeView");
                    if (treeView == null) {
                        console.log("treeView is null!");
                        return;
                    }
     
                    console.log(e);
     
                    treeView.setDataSource(data);
                  });
               }

     

     

  2. Veselin Tsvetanov
    Admin
    Veselin Tsvetanov avatar
    1053 posts

    Posted 28 Oct Link to this post

    Hi Sam,

    In order to properly build the full hierarchy on the client, you will have to createHerarchicalDataSource object and pass it to the setDataSource() call:

    var dataSource = new kendo.data.HierarchicalDataSource({
    	data: data,
    	schema: {
    		model: {
    			id: "Id",
    			children: "Children",
    			hasChildren: "HasChildren",
    			fields: {
    				Name: { type: "string" }
    			}
    		}
    	}
    });
    
    treeView.setDataSource(dataSource);

    Attached you will find a small sample implementing the above.

    Regards,
    Veselin Tsvetanov
    Progress Telerik

    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
  3. Sam
    Sam avatar
    7 posts
    Member since:
    Sep 2019

    Posted 28 Oct in reply to Veselin Tsvetanov Link to this post

    Thank you.  That was the missing part.  However, after this initial load of the tree, I want the user to be able to expand other nodes and load them on demand.  It seems that's not working now as the id field isn't getting passed to the controller method.
  4. Veselin Tsvetanov
    Admin
    Veselin Tsvetanov avatar
    1053 posts

    Posted 30 Oct Link to this post

    Hello Sam,

    I am afraid that you won't be allowed to mix remote DataSource configuration with a local one. Initially, the TreeView is configured to read its items from the GetLocationChildren() action of the Home controller. After resetting the DataSource to use the items obtained with the manual AJAX call, the initial DataSource is no longer assigned to the TreeView. Instead, the local data returned from the above AJAX call will be used in the widget.

    If you need to keep the Read endpoint configuration, you will have to approach the scenario in a different way. Instead of manually calling a controller action, you should set the AutoBind() option of the TreeView helper to false. Then upon a button click, you should trigger Read() on the TreeView DataSource. With that request, you should also send the search parameter to the remote, so that the returned items should be filtered. Also, do not return their nested child items, as those will be requested upon parent expand.

    Attached you will find a small sample implementing the above changes.

    Regards,
    Veselin Tsvetanov
    Progress Telerik

    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
Back to Top