问题
I am using Kendo UI TreeView to load hierarchical data in my webpage. By default, I am loading data upto 3 levels (ie Root -> Root directs -> Root directs' directs). I need a way to lazily load the remaining nodes as user expands further down the tree. Also, the already fetched data must be cached locally to avoid unnecessary calls for already expanded nodes. I am new to Kendo UI and do not have enough time to go through documentation. The json looks like
{
Id: '1',
ParentId: '-1',
Payload: {... }
Children: [
Id: '2',
ParentId: '1',
PayLoad: {...},
Children: [{...}]
]
....
}
Can someone point out to code samples ? How much of the above is supported out of box by Kendo ?
Thanks in advance.
回答1:
That functionality is not supported by the out of the box configuration, but can be achieved through a custom transport. Here's how to create hybrid data sources that work with the localData
array if the items are available, and otherwise perform requests to the server.
var localData = [
{ id: 1, text: "Node 1", hasChildren: true, items: [
{ id: 101, text: "Node 1.1", hasChildren: true, items: [
{ id: 10101, text: "Node 1.1.1" }
] }
] },
{ id: 2, hasChildren: true, text: "Node 2" },
{ id: 3, hasChildren: true, text: "Node 3" }
];
function get(data, id) {
if (!id) {
return data;
} else {
for (var i = 0; i < data.length; i++) {
if (data[i].id == id) {
return data[i].items;
} else if (data[i].items) {
var result = get(data[i].items, id);
if (result) return result;
}
}
}
}
var homogeneous = new kendo.data.HierarchicalDataSource({
transport: {
read: function (options) {
var id = options.data.id;
var data = get(localData, id);
if (data) {
options.success(data);
} else {
// mock call to server with static data
// you can use $.ajax() and call options.success(data) on success
setTimeout(function() {
options.success([
{ id: id + 1, text: "Remote node 1", hasChildren: false },
{ id: id + 2, text: "Remote node 2", hasChildren: true }
]);
}, 1000);
}
}
},
schema: {
model: {
id: "id"
}
}
});
$("#tree").kendoTreeView({
dataSource: homogeneous
});
<link href="http://cdn.kendostatic.com/2013.1.319/styles/kendo.common.min.css" rel="stylesheet" />
<link href="http://cdn.kendostatic.com/2013.1.319/styles/kendo.default.min.css" rel="stylesheet" />
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://cdn.kendostatic.com/2013.1.319/js/kendo.web.min.js"></script>
<div id="tree"></div>
回答2:
After some more work, I got this to work. I'm still not sure why the localData variable is needed, since the Kendo treeview doesn't seem to use it once a node is already in there. Here's my solution anyhow:
<div id="treeview"> </div>
<script>
var serviceRoot = "http://<local name>:58754/api/";
var localData;
$(document).ready(function () {
var homogeneous = new kendo.data.HierarchicalDataSource({
transport: {
read: function (options) {
if (typeof options.data.ID != 'undefined') {
var id = options.data.ID;
var data = getNextLevel(localData, id);
if (data) {
options.success(data);
} else {
var currentnode = get(localData, id);
if (currentnode.Level == 1) {
$.ajax({
url: serviceRoot + "tree",
data: 'ID=' + currentnode.ID + '&Level=' + currentnode.Level,
type: "Get",
success: function (result) {
setTimeout(function () {
var res = result;
addToLocalData(localData, res, currentnode.ID);
options.success(res);
}, 1000);
},
error: function (result) {
options.error(result);
}
});
} else {
if (currentnode.Level == 2) {
$.ajax({
url: serviceRoot + "tree",
data: 'ID=' + currentnode.ID + '&Level=' + currentnode.Level,
type: "Get",
success: function (result) {
setTimeout(function () {
var res = result;
addToLocalData(localData, res, currentnode.ID);
options.success(res);
}, 1000);
},
error: function (result) {
options.error(result);
}
});
}
}
}
}
else {
$.ajax({
url: serviceRoot + "tree",
data: 'ID='+ null +'&Level='+ null,
type: "Get",
success: function (result) {
setTimeout(function () {
options.success(result);
}, 1000);
localData = result;
},
error: function (result) {
options.error(result);
}
});
}
}
},
schema: {
model: {
id: "ID",
hasChildren: "HasChildren"
}
}
});
$("#treeview").kendoTreeView({
dataSource: homogeneous,
dataTextField: "Name"
});
});
//Checks if nodes are already in the tree and returns it if it does
function getNextLevel(data, id) {
if (!id) {
return data;
} else {
for (var i = 0; i < data.length; i++) {
if (data[i].ID == id) {
return data[i].Items;
} else if (data[i].Items) {
for (var j = 0; j < data[i].Items.length; j++) {
if (data[i].Items[j].ID == id) {
return data[i].Items[j].Items;
}
}
}
}
}
}
//Get Tree object for a given ID
function get(data, id) {
if (id) {
for (var i = 0; i < data.length; i++) {
if (data[i].ID == id) {
return data[i];
}
else if (data[i].Items) {
for (var j = 0; j < data[i].Items.length; j++) {
if (data[i].Items[j].ID == id) {
return data[i].Items[j];
}
}
}
}
}
return null;
}
//Add newly read nodes to cached tree
function addToLocalData(localdata, data, id) {
if (!id) {
return localdata;
} else {
for (var i = 0; i < localdata.length; i++) {
if (localdata[i].ID == id) {
localdata[i].Items = data;
return;
} else {
if (localdata[i].Items) {
for (var j = 0; j < localdata[i].Items.length; j++) {
if (localdata[i].Items[j].ID == id) {
localdata[i].Items[j].Items = data;
return;
}
}
}
}
}
}
}
</script>
I'm using a stored procedure to read values from 3 tables into a Tree object. Here is the code for the Tree object:
public class Tree
{
public Guid ID { get; set; }
public string Name { get; set; }
public bool HasChildren { get; set; }
public int Level { get; set; }
public IEnumerable<Tree> Items { get; set; }
}
And my Stored procedure:
ALTER PROCEDURE [dbo].[GetTreeItems]
@ID uniqueidentifier, @CurrentLevel int
AS BEGIN SET NOCOUNT ON;
if @CurrentLevel is null
select IDStation as ID, StationName as Name, null as IDParent, 1 as [Level] ,
case when (select COUNT(*) from Unit where Unit.IDStation = Station.IDStation) > 0 then 1 else 0 end as HasChildren
from Station
order by [Level], Name
--union
else if @CurrentLevel = 1
select IDUnit as ID, UnitName as Name, Station.IDStation as IDParent, 2 as [Level],
case when (select COUNT(*) from Component where Component.IDUnit = Unit.IDUnit) > 0 then 1 else 0 end as HasChildren
from Unit inner join Station on Station.IDStation = Unit.IDStation
where Station.IDStation = @ID
order by [Level], Name
--union
if @CurrentLevel = 2
select IDComponent as ID, ComponentName as Name, Unit.IDUnit as IDParent,
3 as [Level], 0 as HasChildren
from Component inner join Unit on unit.IDUnit = Component.IDUnit
where Unit.IDUnit = @ID
order by [Level], Name
END
来源:https://stackoverflow.com/questions/20470822/lazy-load-in-kendo-ui-treeview-with-caching