CoffeeBean CoffeeBean - 23 days ago 5
Javascript Question

Populating kendo-tree using from Json

I am in Angular environment using Kendo. All I want to do is following:


  1. Take Json

  2. Produce Kendo tree using it



I have tried it with simple data and it seems to work fine. But this time I have somewhat complex data and it seems like it does not work well with complex Json. I have been trying to have it render Json but it seems like it keeps on thinking and never comes back. I have created a sample Dojo for reference:

http://dojo.telerik.com/EdOqE

I am not sure what am I doing wrong but it just does not seem to work. Can anyone help me with this please?

Answer

I presume you have controll over the resultant json, because you'll have to change it a little to fit the TreeView's expected format. Check this out:

{
    "items": [{ // Projects
        "Id": 0,
        "Name": "Your Example Project",
        "CreatedOn": "",
        "hasChildren": true,
        "items": [{ // Analyses
            "Id": 0,
            "Name": "1.0 - Your Example Run",
            "CreatedOn": "",
            "hasChildren": true,
            "items": [{ // Samples
                "Id": 0,
                "Name": "Sample 1",
                "hasChildren": false,
                "Description": "ample frample sample"
            }, {
                "Id": 0,
                "Name": "Sample 2",
                "hasChildren": false,
                "Description": null
            }]
        }]
    }]
};

The above json is what I did to work in the widget. First of all, the collection properties were renamed to items. All of them, in all levels. With that, kendo will know how property it should deal with. A hasChildren property was added to let it know when it has to show the expand icon. Otherwise it will show the expand option even if the item doesn't haves any children. So user clicks it and get an empty result.

This is the widget initialization options:

{
    dataSource: new kendo.data.HierarchicalDataSource({ 
        data: things,
        schema: {
            data: "items"
        }
    }),
    dataTextField: "Name"
};   

With schema.data I tell which property kendo will deal as the collection item. The dataSource expects an array, but if you give him an object, you have to set this property. If it was an array, then kendo would look for item property of each child for default. dataTextField is the name of the property it will use as the label.

Demo

Here is another demo with the data as an array. No need to set schema.data.

Update:

I was afraid you would say that. Yes, there is a way to deal with the data if you can't change it in the server-side. You have to intercept the data at the schema.parse() method and change the resultant data object property to items, so then the widget will understand:

schema: {
    data: "items",
    parse: function(data) {
        if (data.hasOwnProperty("Projects")) {
            return { items: data.Projects };
        }
        else if (data.hasOwnProperty("Analyses")) { 
            return { items: data.Analyses };
        }
        else if (data.hasOwnProperty("Samples")) { 
            return { items: data.Samples };
        }
    }
}

Demo

Every node when opened will call parse with items collection as data parameter. You have to return a new object with the property name as items instead of Projects, Analysis or Samples.


I forgot you can't touch the data, so can't add hasChildren property as well. Then you have to add a tiny logic into parse to set those properties in each level, otherwise the expand icon would not appear:

schema: {
    data: "items",
    parse: function(data) {
        if (data.hasOwnProperty("Projects")) {

            data.Projects.forEach(p => {
                p.hasChildren = false;

                if (p.hasOwnProperty("Analyses")) {
                    p.hasChildren = true;
                }
            });

            return { items: data.Projects };
        }
        else if (data.hasOwnProperty("Analyses")) { 

            data.Analyses.forEach(a => {
                a.hasChildren = false;

                if (a.hasOwnProperty("Samples")) {
                    a.hasChildren = true;
                }
            });

            return { items: data.Analyses };
        }
        else if (data.hasOwnProperty("Samples")) { 
            return { items: data.Samples };
        }
    }
}

Demo

It is ugly, I know. But get used to Kendo, it is the it goes with it.