This is a migrated thread and some comments may be shown as answers.

MVC TreeList Load on Demand

18 Answers 419 Views
TreeList
This is a migrated thread and some comments may be shown as answers.
John
Top achievements
Rank 1
John asked on 30 Aug 2016, 04:12 PM

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)
)

18 Answers, 1 is accepted

Sort by
0
Viktor Tachev
Telerik team
answered on 01 Sep 2016, 11:00 AM
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
0
John
Top achievements
Rank 1
answered on 06 Sep 2016, 10:56 PM

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.  

0
John
Top achievements
Rank 1
answered on 06 Sep 2016, 11:07 PM

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);
        }

 

0
Viktor Tachev
Telerik team
answered on 08 Sep 2016, 11:22 AM
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
0
John
Top achievements
Rank 1
answered on 08 Sep 2016, 12:49 PM

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??

0
Viktor Tachev
Telerik team
answered on 12 Sep 2016, 07:24 AM
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
0
John
Top achievements
Rank 1
answered on 12 Sep 2016, 03:33 PM

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.

 

 

0
John
Top achievements
Rank 1
answered on 12 Sep 2016, 11:48 PM

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.

 

 

0
Viktor Tachev
Telerik team
answered on 14 Sep 2016, 10:21 AM
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
0
John
Top achievements
Rank 1
answered on 14 Sep 2016, 02:46 PM

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

 

 

0
Viktor Tachev
Telerik team
answered on 16 Sep 2016, 08:52 AM
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
0
John
Top achievements
Rank 1
answered on 16 Sep 2016, 10:41 PM

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

0
Viktor Tachev
Telerik team
answered on 20 Sep 2016, 11:43 AM
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
0
John
Top achievements
Rank 1
answered on 20 Sep 2016, 11:53 PM
Ok - Viktor have a runnable example project that does not work either.  How do I submit that runnable project to you???
0
Viktor Tachev
Telerik team
answered on 21 Sep 2016, 12:58 PM
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
0
binta
Top achievements
Rank 1
answered on 31 Mar 2017, 06:01 AM

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

0
Viktor Tachev
Telerik team
answered on 03 Apr 2017, 01:07 PM
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.
0
binta
Top achievements
Rank 1
answered on 04 Apr 2017, 05:31 AM

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

Tags
TreeList
Asked by
John
Top achievements
Rank 1
Answers by
Viktor Tachev
Telerik team
John
Top achievements
Rank 1
binta
Top achievements
Rank 1
Share this question
or