MVC TreeList Load on Demand

19 posts, 0 answers
  1. John
    John avatar
    16 posts
    Member since:
    Jul 2016

    Posted 30 Aug 2016 Link to this post

    Hi,

     

    Trying to create a TreeList view, but the data set is too large. exceed maxJson limit.  

    So I'd like to load on demand.  Bring back the 1st level where the parentId string is null and then as each node is cliked have it return the next set of data.  I've a similar thread where the suggestion was to look at the emploeedirectory example, but don't see how that works per say. 

    While trouble-shooting have noticed that trying to restrict the intial data request to just the top items where parentId is null does not work.  Tried to set default value for parentId as well but still does not work - "No Records to display"

    However, changing the default parentId to a value and retricting the data query to that same value does return the items where their parent is the specified default value. 

    I'm assuming there would be an inital query that brings back the top level items, but how would it show if there are sub items to select?  

    Secondly, when a node is clicked would there need to be a clicked event that calls the controller to update the TreeList?  

    Here is the controller method:

    public ActionResult GetBoms([DataSourceRequest] DataSourceRequest request)
            {
                var db = new EmsDashDev();
                var results = db.NHAItems.ToList<NHAItems>();
                var results1 = results.ToTreeDataSourceResult(request,
                    e => e.ComponentNumber,
                    e => e.NextHigherAssembly);
                return Json(results1);
            }

    And the view code

    @(Html.Kendo().TreeList<EMSCommitScheduleApp.Models.NHAItems>()
        .Name("treelist")
        .AutoBind(true)
        
        .Columns(columns =>
        {
            columns.Add().Field(e => e.ComponentNumber).Width(280);
            columns.Add().Field(e => e.ItemNumber).Width(160);
            columns.Add().Field(e => e.Description);
            columns.Add().Field(e => e.Qty).Width(80);
            columns.Add().Field(e => e.NextHigherAssembly).Width(280);
            columns.Add().Field(e => e.LevelZeroAssembly);
            columns.Add().Field(e => e.AssemblyIndicator).Title("Make");
        })
        .Filterable()
        .Sortable()
        .DataSource(dataSource => dataSource
            .Read(read => read.Action("GetBoms", "Home"))
            .ServerOperation(true)
            .Model(m => {
                m.Id(f => f.ComponentNumber);
                m.ParentId(f => f.NextHigherAssembly);
                m.Expanded(false);
                m.Field(f => f.ComponentNumber);
                m.Field(f => f.ItemNumber);
                m.Field(f => f.Description);
                m.Field(f => f.Qty);
                m.Field(f => f.NextHigherAssembly);
                m.Field(f => f.LevelZeroAssembly);
                m.Field(f => f.AssemblyIndicator);
            })
            
        )
        .Height(540)
    )

  2. Viktor Tachev
    Admin
    Viktor Tachev avatar
    1644 posts

    Posted 01 Sep 2016 Link to this post

    Hello John,

    Please check the following example that illustrates how you can implement the behavior you are looking for. The items in the sample are loaded per-level only.


    Try to use similar approach and you should be able to implement the behavior you are looking for.

    Regards,
    Viktor Tachev
    Telerik by Progress
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  3. John
    John avatar
    16 posts
    Member since:
    Jul 2016

    Posted 06 Sep 2016 Link to this post

    Thanks Viktor.

    Having issues working out this still given your example.  I have a compile error in the controller method 

    It does not like the signature : the type string must be a non-nullable value type in order to use it as parameter 'T'  ...

     

    public ActionResult GetBoms([DataSourceRequest] DataSourceRequest request, string? id)
            {
                var db = new EmsDashDev();
                            
                var results = db.NHAItems.Where(a => a.NextHigherAssembly == null);
                var results1 = results.ToTreeDataSourceResult(request,
                    e => e.ComponentNumber,
                    e => e.NextHigherAssembly,
                    e => id.HasValue ? true : false,
                    e => e.ToNHAItemModel()
                    );
                return Json(results);
            }

    Any thoughts on how to code this correctly to handle a string versus an int at least that seems to be where I'm getting stuck at the moment.  

  4. John
    John avatar
    16 posts
    Member since:
    Jul 2016

    Posted 06 Sep 2016 Link to this post

    And when I try to use a non-nullable type I get a Cannot convert lambda expression to type Mvc.ModelStateDictionary because it is not a delegate type.

    public ActionResult GetBoms([DataSourceRequest] DataSourceRequest request, string id)
            {
                var db = new EmsDashDev();
                            
                var results = db.NHAItems.Where(a => a.NextHigherAssembly == null);
                var results1 = results.ToTreeDataSourceResult(request,
                    e => e.ComponentNumber,
                    e => e.NextHigherAssembly,
                    e => id.HasValue ? true : false,
                    e => e.ToNHAItemModel()
                    );
                return Json(results1);
            }

     

  5. Viktor Tachev
    Admin
    Viktor Tachev avatar
    1644 posts

    Posted 08 Sep 2016 Link to this post

    Hello John,

    Try to retrieve the necessary fields before calling ToDataSourceResult(). The method would look similar to the following. Give it a try and see how it works for you.

    public ActionResult GetBoms([DataSourceRequest] DataSourceRequest request, string id)
    {
        var db = new EmsDashDev();
                     
        var results = db.NHAItems.Where(a => a.NextHigherAssembly == null);
        var results1 = results.Select(e=> new
                                            {
                                             ComponentNumber = e.ComponentNumber,
                                             NextHigherAssembly = e.NextHigherAssembly,
                                             HasValue = id.HasValue
                                            }).ToDataSourceResult(request);
        return Json(results1);
    }

     

    Regards,
    Viktor Tachev
    Telerik by Progress
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  6. John
    John avatar
    16 posts
    Member since:
    Jul 2016

    Posted 08 Sep 2016 in reply to Viktor Tachev Link to this post

    Hi Viktor - still no dice.

    Here is the modified code.

    public ActionResult GetBoms([DataSourceRequest] DataSourceRequest request, string id)
    {
    var db = new EmsDashDev();
    var results = db.NHAItems.Where(a => a.NextHigherAssembly == null);
    var results1 = results.Select(e => new
    {
    Component = e.ComponentNumber,
    NextHigherAssembly = e.NextHigherAssembly,
    HasValue = id.HasValue
    }).ToTreeDataSourceResult(request);


    return Json(results);
    }

    Error 1 Cannot convert lambda expression to type 'System.Linq.Expressions.LambdaExpression' because it is not a delegate type 

    Error 2 Cannot assign method group to anonymous type property 

    Still get the above errors??

  7. Viktor Tachev
    Admin
    Viktor Tachev avatar
    1644 posts

    Posted 12 Sep 2016 Link to this post

    Hello John,

    Would you try to call ToList() before the call to ToDataSourceResult and see how the behavior changes?

    In case the issue persists please send us a runnable sample where the behavior is replicated so we can examine it locally.

    Regards,
    Viktor Tachev
    Telerik by Progress
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  8. John
    John avatar
    16 posts
    Member since:
    Jul 2016

    Posted 12 Sep 2016 in reply to John Link to this post

    Hi Viktor,

     

    Ok - so adding toList didn't help, but changing id.HasValue to id.HasValue() did work in terms of compiling. However, even though results1 contains 15 entries the TreeList does not display any results.  

    Not sure how to send you a "working example" , but will if I know how.

     

     

  9. John
    John avatar
    16 posts
    Member since:
    Jul 2016

    Posted 12 Sep 2016 Link to this post

    Ok - A bit more progress. 

    The following code returns a data set as intended but only when I define the default value versus a null.

    public ActionResult GetBoms([DataSourceRequest] DataSourceRequest request, string id)
    {
    var db = new EmsDashDev();
    var results = db.NHAItems.ToList<NHAItems>();
    var results1 = results.Select(e => new
    {
    ComponentNumber = e.ComponentNumber,
    NextHigherAssembly = e.NextHigherAssembly
    }).ToTreeDataSourceResult(request);
    // This returns no records for some reason
    var results2 = results.ToTreeDataSourceResult(request,
    e => e.ComponentNumber,
    e => e.NextHigherAssembly,
    e => id.HasValue() ? true : false,
    e => e.ToNHAItemModel()
    );
    return Json(results1);
    }

    in the UI configuration is this then works  - m.ParentId(f => f.NextHigherAssembly).DefaultValue("some valid pn");

    However if I use m.ParentId(f => f.NextHigherAssembly).DefaultValue(null); which should represent the top level nodes it does not work.  Tried string.Empty, but it does not work either nor would I expect it to.

    So it seems to me the TreeList Widget does not handle the strings correctly when they are the id and parentId.

     

     

  10. Viktor Tachev
    Admin
    Viktor Tachev avatar
    1644 posts

    Posted 14 Sep 2016 Link to this post

    Hello John,

    The default value for ParentId will be null. This means that if the root items in your data source have the value set to null you do not need to explicitly set DefaultValue.


    Regards,
    Viktor Tachev
    Telerik by Progress
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  11. John
    John avatar
    16 posts
    Member since:
    Jul 2016

    Posted 14 Sep 2016 in reply to Viktor Tachev Link to this post

    Hi Viktor,

     

    I tried to explicitly specify default = null because not using anything did not produce any results.  The only time I have results is specifying a level down from the top as shown below commented out.

    .DataSource(dataSource => dataSource
    .Read(read => read.Action("GetBoms", "Home"))
    .ServerOperation(false)
    .Model(m => {
    m.Id(f => f.ComponentNumber);
    m.ParentId(f => f.NextHigherAssembly);// .DefaultValue("3890AS000116-01");
    m.Expanded(false);
    m.Field(f => f.ComponentNumber);
    m.Field(f => f.NextHigherAssembly);
    }) )

    I'm close to a working TreeList just need to resolve why not specifying a default does not work.

    Thanks,

    John

     

     

  12. Viktor Tachev
    Admin
    Viktor Tachev avatar
    1644 posts

    Posted 16 Sep 2016 Link to this post

    Hi John,

    It would be hard to pinpoint what is causing the behavior without replicating it locally.

    I tested the load-on-demand feature in TreeList and it is working as expected on my end. You can see the relevant parts of the code in the following snippets.

    @(Html.Kendo().TreeList<Kendo.Mvc.Examples.Models.TreeList.EmployeeDirectoryModel>()
        .Name("treelist")
        .Columns(columns =>
        {
            columns.Add().Field(f => f.FirstName).Width(250).Title("First Name");
            columns.Add().Field(e => e.LastName).Title("Last Name");
            columns.Add().Field(e => e.Position);
            columns.Add().Field(e => e.Extension).Title("Ext").Format("{0:#}");
        })
        .DataSource(dataSource => dataSource
            .Read(read => read.Action("Index", "EmployeeDirectory"))
            .Model(m => {
                m.Id(f => f.EmployeeId);
                m.ParentId(f => f.ReportsTo);
                m.Field(f => f.FirstName);
                m.Field(f => f.LastName);
                m.Field(f => f.ReportsTo);
            })
        )
    )


    public JsonResult Index([DataSourceRequest] DataSourceRequest request, int? id)
    {
        var result = GetDirectory().ToTreeDataSourceResult(request,
            e => e.EmployeeID,
            e => e.ReportsTo,
            e => id.HasValue ? e.ReportsTo == id : e.ReportsTo == null,
            e => e.ToEmployeeDirectoryModel()
        );
     
        return Json(result, JsonRequestBehavior.AllowGet);
    }


    You can also test the behavior by downloading the offline examples of the components. The code above is from the Remote Data Binding example.

    Regards,
    Viktor Tachev
    Telerik by Progress
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  13. John
    John avatar
    16 posts
    Member since:
    Jul 2016

    Posted 16 Sep 2016 Link to this post

    Hi Viktor,

    Already be using the example you have referenced.  That being said this following block of code returns 15 records as expected.

    In your reference example what role does the hasChildren variable play in displaying records? 

    I was not able to use this statement: e=> id.HasValue  and had to use id != null as and it is my understanding it is equivalent. 

    var results2 = results.ToTreeDataSourceResult(request,
    e => e.ComponentNumber,
    e => e.NextHigherAssembly,
    e => id != null ? e.NextHigherAssembly == id : e.NextHigherAssembly == null,
    e => e.ToNHAItemModel()
    );

    Attached is a screen shot showing the 15 elements come back as expected but nothing ends up in the TreeList and thoughts as to why that may be?  What else can I do to figure out why the grid is empty?

    Thanks,

     

    John

  14. Viktor Tachev
    Admin
    Viktor Tachev avatar
    1644 posts

    Posted 20 Sep 2016 Link to this post

    Hello John,

    If there are 15 records returned from the data source and passed to ToTreeDataSourceResult() then the items should be displayed in the TreeList.

    However, it would be hard to determine why you are not seeing the items in the TreeList without replicating the problem locally. Please assemble a runnable sample where the issue is replicated and send it to us. Thus, we will be able to examine the behavior and look for its cause.


    Regards,
    Viktor Tachev
    Telerik by Progress
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  15. John
    John avatar
    16 posts
    Member since:
    Jul 2016

    Posted 20 Sep 2016 in reply to Viktor Tachev Link to this post

    Ok - Viktor have a runnable example project that does not work either.  How do I submit that runnable project to you???
  16. Viktor Tachev
    Admin
    Viktor Tachev avatar
    1644 posts

    Posted 21 Sep 2016 Link to this post

    Hello John,

    You can submit a support ticket and submit the project as attachment there. This way we can debug the code and look for the cause of the behavior you are seeing.


    Regards,
    Viktor Tachev
    Telerik by Progress
    Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
  17. binta
    binta avatar
    3 posts
    Member since:
    Mar 2017

    Posted 31 Mar Link to this post

    Hi 

    Please help me out. I am breaking my head to achieve the load on demand treelist in kendo. I have followed the instructions as per the url http://demos.telerik.com/aspnet-mvc/treelist/remote-data-binding. But nothing worked out. My scenario is like that I need to load the parent nodes when loading the page first. Then on clicking the parent node, need to fire a call to get the child nodes. For me, it load the parent nodes first, but I can't see the expand icon coming up for nodes having children. Just see the attached image. I don't know what I'm doing wrong. Attaching the view page code and also the controller methods. Please let me know what is the issue? Well appreciated, if you could share some code for sample other than the demo sample.

    View code

    ----------------------

     <div>

                    @(Html.Kendo().TreeList<TelerikMvcApp1.Models.AssetModel>()
                    .Name("assetTreeList")
                    .Columns(columns =>
                    {
                        columns.Add().Field(a => a.AssetName).Width(70).Expandable(true);
                    })
                    .Sortable()
                    .DataSource(dataSource => dataSource
                        .Read(read => read.Action("LoadTree", "Home"))
                        .ServerOperation(false)
                        .Model(m =>
                        {
                            m.Id(e => e.AssetId);
                            m.ParentId(e => e.ParentAssetId);
                            m.Field(e => e.AssetName);
                            m.Field(e => e.ParentAssetId);
                        })
                        )
                    .Scrollable(true)
                    .Height(540)
                   //.Events(e => e
                   ////.DataBound("onAssetTreeListDataBound")
                   //// ////.Change("treelist_change")
                   //)
                    )

                </div>

    Controller Methods

    -------------------------------------------------

     public IEnumerable<AssetModel> GetAssetTreeListBasedOnPermissions()
            {
                try
                {
                    List<AssetModel> list = new List<AssetModel>();
                    list.Add(new AssetModel { AssetId = 1, ParentAssetId = null, AssetName = "asset1" });
                    list.Add(new AssetModel { AssetId = 2, ParentAssetId = 1, AssetName = "asset2" });
                    list.Add(new AssetModel { AssetId = 3, ParentAssetId = null, AssetName = "asset3" });
                    list.Add(new AssetModel { AssetId = 4, ParentAssetId = 2, AssetName = "asset4" });

                    IEnumerable<AssetModel> enumlist = list
                        .Select(x => new AssetModel
                        {
                            AssetId = x.AssetId,
                            ParentAssetId = x.ParentAssetId,
                            AssetName = x.AssetName
                        });
                    return enumlist;

                  
                }
                catch (Exception ex)
                {
                    return null;
                }
            }

            public JsonResult LoadTree([DataSourceRequest] DataSourceRequest request, int? id)
            {
                var result = GetAssetTreeListBasedOnPermissions().ToTreeDataSourceResult(request,
                    e => e.AssetId,
                    e => e.ParentAssetId,
                    e => id.HasValue ? e.ParentAssetId == id : e.ParentAssetId == null,
                    e=>e
                );

                return Json(result, JsonRequestBehavior.AllowGet);
            }

    Model class

    ------------------------

     public class AssetModel
        {
            public long AssetId { get; set; }
            public long? ParentAssetId { get; set; }
            public string AssetName { get; set; }
            public bool HasChildren { get; set; }
        }

    Thanks in advance

    Binta Prasad

  18. Viktor Tachev
    Admin
    Viktor Tachev avatar
    1644 posts

    Posted 03 Apr Link to this post

    Hi Binta,

    Please submit each unrelated query you may have in a separate thread. This way the information in a single thread will be consistent and easier to use as reference. 

    With that said, please ensure that you are not using any custom styles. Remove any custom CSS applied on the page and see how the behavior changes. 

    Also, check the browser console by pressing F12 and see if there are any errors listed. 

    Furthermore, make sure that you are using the latest version of the components. The current release is 2017.1.223.


    Regards,
    Viktor Tachev
    Telerik by Progress
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  19. binta
    binta avatar
    3 posts
    Member since:
    Mar 2017

    Posted 04 Apr in reply to Viktor Tachev Link to this post

    Hi Victor,

    Thanks for the response.

    See the thread below where I have posted the same query. But I didn't receive any reply.

    http://www.telerik.com/forums/kendo-mvc-treelist-load-on-demand-not-showing-expand-icon-while-loading-parent-nodes

    By the way I don't have any custom styles applied on the page. Also there are no errors listed in the console.

    I am also using the current release version of Kendo. I hope the remaining conversation can be held in the new thread.

    Can you point out what is the error in my code? Any other solution will be a great help.

     

    Thanks

    Binta Prasad

Back to Top