Is there a way to check multiple checkboxes at once through the TreeView API? I have a TreeView with a large number of nodes (up to ~10,000) and a requirement to be able to save/reload checkbox selections. At the moment to reload them I'm clicking each of the required checkboxes via javascript, but that fires off the events to re-evaluate the checked/indeterminate/unchecked states of all parent nodes for each checkbox, which is extremely time-consuming.
Ideally I'd like to be able to pass the TreeView a list of checkboxes to check and have them all done in one go, but any pointers on how to make this more efficient would be gratefully received.
Many thanks,
Chris
23 Answers, 1 is accepted
If you set the checkbox checked property directly, this will not kick off the indeterminate check. Afterwards you can kick off an update of the indeterminate field. At this time, this can be done through the _updateIndeterminateInitial "private" method, as seen in this jsBin. We have opened this method for public use and it will be available in the upcoming 2013.Q2 release next week -- so you will need to call treeview.updateIndeterminate() after upgrading.
Regards,Alex Gyoshev
Telerik
That's considerably faster than clicking all of the nodes!
Regards,
Chris
I've got a minor issue with this, please see the jsBin here.
If you
- expand the top-level Node 0 and some nodes underneath that
- click the 'Check all nodes' button
- uncheck the top-level Node 0
- click 'Check all nodes'
- uncheck the top-level Node 0
Thanks,
Chris
There is indeed a problem with that workaround. The treeview isn't notified that a node is unchecked internally. I would suggest a different approach - to check only the first level nodes and trigger their change events: http://jsbin.com/ITayEWe/5/edit
Regards,Atanas Korchev
Telerik
Unfortunately my requirement is to check a predefined selection of leaf node checkboxes (unchecking all of the others) and then to update the indeterminate status of the checkboxes in the tree - checking all of the checkboxes is just the specific instance of this where the problem occurs.
Setting the checkboxes to checked and triggering the change event doesn't give the performance required when dealing with around 10,000 nodes.
Many thanks,
Chris
Can you please update the last jsbin to demonstrate the actual problem you are having? Perhaps we can find the proper workaround.
Regards,Atanas Korchev
Telerik
The jsBin at http://jsbin.com/ITayEWe/8/edit demonstrates the problem.
as before, the steps to reproduce are:
- expand the top-level Node 0 and some nodes underneath that
- click the button
- uncheck the top-level Node 0
- click the button
- uncheck the top-level Node 0
Chris
I think I found a workaround: http://jsbin.com/ITayEWe/11/edit
$("#tree").on("change", ":checkbox", function(e) {
var node = $(e.currentTarget).closest(".k-item");
var dataItem = tree.dataSource.getByUid(node.attr("data-uid"));
dataItem.trigger("change", { field: "checked" });
});
Regards,
Atanas Korchev
Telerik
Sorry for the delay in replying, took me a while to get round to testing this.
That fix works fine,
Thanks!
Chris
then you have some code below the link.
I am trying to use the code you have listed $("#tree....
When I get to the var dataItem = tree.dataSource.getByUid it fails on runtime.
No matter how I try to format the string it comes back as Cannot call method 'getByUid' of undefined.
The associated jsbin does not have this code in it.
Do you have an example where you actually use this code snip-it?
It is exactly what I need if I could only get it to work.
Here is the updated demo: http://jsbin.com/ITayEWe/51/edit
Also here is the code in case something happens to it:
<
script
>
var tree = $("#tree").kendoTreeView({
dataSource: {
data: populate(2)
},
loadOnDemand: false,
checkboxes: {
checkChildren: true
}
}).data("kendoTreeView");
$("#tree").on("change", ":checkbox", function(e) {
var node = $(e.currentTarget).closest(".k-item");
var dataItem = tree.dataSource.getByUid(node.attr("data-uid"));
dataItem.trigger("change", { field: "checked" });
});
$("button").click(function(e) {
var leafCheckboxes = $('.k-item > div:only-child input[type="checkbox"]');
leafCheckboxes = leafCheckboxes.slice(0, leafCheckboxes.length - 1);
leafCheckboxes.prop("checked", true);
tree.updateIndeterminate(tree.wrapper);
});
// generate 10^(levels+1) items
function populate(levels) {
var data = [];
for (var i = 0; i <
2
; i++) {
var node = { text: "Node " + i };
if (levels > 0) {
node.items = populate(levels - 1);
}
data.push(node);
}
return data;
}
</
script
>
Regards,
Atanas Korchev
Telerik
How would this look using MVC and razor?
The JavaScript code should be exactly the same. Replace $("#tree") with the Name() of your treeview (don't forget the "#" in the beginning).
Regards,
Atanas Korchev
Telerik
The line that is holding me up is the line assigning to the dataItem
var dataItem = tree...
In the script you are assigning var tree = $("#tree")...
but tree is always null.
Here is my code
<script type="text/javascript">
function onChange(e) {
window.alert("In Change");
}
function onDataBound(arg) {
window.alert("List view loading "+ nodeType);
}
$("#nodeTypeTree").on("change", ":checkbox", function (e) {
var node = $(e.currentTarget).closest(".k-item");
var dataItem = nodeTypeTree.dataSource.getByUid(node.attr("data_uid"));
alert(node.attr("data_uid"));
dataItem.trigger("change", { field: "checked" });
});
$("showCheckedBtn").click(function (e) {
var checkedList = $(":checkbox");
checkedList.prop("checked", true);
nodeTypeTree.updateIndeterminate(nodeTypeTree.wrapper);
});
</script>
<script type="text/javascript">
function onTreeSelect(e) {
window.alert("In Tree Select " + this.text(e.node));
}
// function that gathers IDs of checked nodes
function checkedNodeIds(nodes, checkedNodes) {
window.alert("In Checked Node Ids");
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].checked) {
checkedNodes.push(nodes[i].id)
}
if (nodes[i].hasChildren) {
checkedNodeIds(nodes[i].children.view(), checkedNodes);
}
}
}
<div id="nodeTypeTree">
@* Kendo TreeView sample gotten from Kendo Samples razor/web/treeview/remote-data*@
@(Html.Kendo().TreeView()
.Name("nodeTypeTree")
.Checkboxes(_chk => _chk
.Name("ckeckedFields")
.CheckChildren(true)
.Template("<input type='checkbox' name='checkedNodes' #= item.isChecked ? 'checked' : '' # value='#= item.id #' />")
)
.DataSource(d => d.Read(r => r.Action("GetNodeTypeForClient","_ClientAttributeMgr")))
.DataTextField("Name")
.Events(events => events
.Select("onTreeSelect").Change("onChange").DataBound("onDataBound")
)
)
</div>
<button id="showCheckedBtn" name="showCheckedBtn">Check State</button>
This happens because the Name() of your treeview is not "tree" as in the original topic. Please replace $("#tree") with $("#your_treeview_name").
Regards,
Atanas Korchev
Telerik
I did use the name of my tree view. I don't have a var called nodeTypeTree but isn't that where you are defining your TreeView? I have a div called nodeTypeTree.
$("#nodeTypeTree").on("change", ":checkbox", function (e) {
var node = $(e.currentTarget).closest(".k-item");
var dataItem = nodeTypeTree.dataSource.getByUid(node.attr("data_uid"));
alert(node.attr("data_uid"));
dataItem.trigger("change", { field: "checked" });
});
The code is executed before the treeview is rendered and this is why $("#nodeTypeTree") returns null - the element doesn't exist yet. You need to put this code after the treeview is rendered:
@(Html.Kendo().TreeView())
<script>
$(function() {
$("#nodeTypeTree").on("change", ":checkbox", function (e) {
var node = $(e.currentTarget).closest(".k-item");
var nodeTypeTree = $("#nodeTypeTree").data("kendoTreeView");
var dataItem = nodeTypeTree.dataSource.getByUid(node.attr("data_uid"));
alert(node.attr("data_uid"));
dataItem.trigger("change", { field: "checked" });
});
});
</script>
You also need to initialize the nodeTypeTree variable before using it.
Regards,
Atanas Korchev
Telerik
I now see an object for the nodeTypeTree and for the node.
however nodeTypeTree.dataSource.getByUid(node.attr("data_uid")) is still undefined.
Maybe I am heading down the wrong rode here.
Ultimately I want to capture all the items that have been checked.
The original thread was for a problem caused by programmatically checking the nodes. Are experiencing the same issue?
You can review the checkboxes demo which shows how to get the checked nodes. You could check both the HTML and ASP.NET MVC versions to see the JavaScript and server-side solutions.
If you need further assistance please start a new forum or support thread.
Regards,
Atanas Korchev
Telerik
I will start a new thread non the less Stating my issue. There might be a different solution.
I need to do something similar, but while using a remote data source. This means that I do not necessarily have all the checked nodes loaded in the tree, but I do have the full path of all the checked nodes, i.e. the id of all the checked nodes ancestors.
How can I set a node to show as indeterminate if I know that one of its descendants will be checked when it is loaded?
Thanks
Colin
Hello Colin,
Since the TreeView does not have a way of knowing this, you may need to manually update the checkbox state after the TreeView has been rendered. You can set the checkbox indeterminate property via jQuery, like this:
$(":checkbox").filter( /* filter out checkboxes that need to be indeterminate */ ).prop("indeterminate", true);
Regards,Alex Gyoshev
Telerik
Thanks for that it is exactly what I needed.
Colin