I have a standard edit page in my application that has in it an igTree.
This tree has a total of 1500 nodes and on load I need to change the checkstate to checked all of the checkboxes that meet a certain criteria that is returned from a dataset loaded via an ajax call.
What I'm currently doing is finding the nodes that need to be checked against the entire collection. This works fine and work as expected.
Where I'm having a problem is the actual performance of checking the checkboxes. I'm hoping there's a better way of doing this. Currently I'm iterating over the collection of nodes that need to be checked and telling igTree to check them.
var t1 = new Date();
var theTree = $("#tree");
for (var i = 0; i < allMatchedNodes.length; i++) {
theTree.igTree("toggleCheckstate", allMatchedNodes[i].element);
}
var t2 = new Date();
var dif = t1.getTime() - t2.getTime();
var Seconds_from_T1_to_T2 = dif / 1000;
var Seconds_Between_Dates = Math.abs(Seconds_from_T1_to_T2);
In the example above, allMatchedNodes has a total of 36 entries and they typically have a child collection which may have another child collection (3 levels).
The problem is this takes a dreadfully long time to complete under IE8, so long in fact that you get the long running script error multiple times.
In the test cases I've run so far, the above reports 65 seconds as the running time. Am I doing something wrong attempting to check the checkboxes in this fashion?Can I remove the child collection from each top level node?
Will igTree be intelligent enough to check all children for me or does it need the children collection to check them? I'm guessing the internal toggleCheckState call is recursively iterating through the children which in this case there are up to three more levels to go through.
Your help is appreciated.
Thank You
Hi there,
First of all the igTree has a checkstate that would recursively check nodes (triState) and one that keeps the checked nodes independent of each other (biState). If your issue is with the triState, meaning the recursion for the checking takes too long, then you can enable loadOnDemand. In the case of all of your data being already loaded and enabling loadOnDemand, you would actually utilize render on demand, meaning DOM elements would be created upon a node being expanded. The nodes would be rendered checked in the case of a triState checkbox mode and a checked parent. Try this out and let me know how it works!
If you have additional questions feel free to ask!
So this leads to a bunch of other questions and comments but this seems to be the right track:
To give you some background here's what's happening on this page.
An initial AJAX call is made via JQuery that retrieves the "hierarchy" where our Hiearchy looks like
Country -> Region -> District -> Store
This call gets the hierarchy data and builds out the treeview. This works and with loadOnDemand as expected it only generates the country nodes initially.
A second AJAX call is made that retrieves all the countries/regions/districts/stores that should be checked in the treeview for the event we're working with. (This is the basic premise of the page. Give the user an easy screen to schedule events nationally/regionally/district level/at a store)
When this second call completes and is successful, we iterate over the selected collection and apply the checks to the treeview.
On to the questions/comments
1) I definitely see load on demand only loading the requested level. In my scenario the top level visible nodes are just three countries: US, Canada, and Mexico. When I click to drill down the nodes are created as expected.
2) How do I programatically set a checkbox to be tri-state partial checked? In my example, the US needs to be a tri-state partial check. The toggleCheckState documentation doesn't seem to indicate that this can be done. It appears to be toggle on/toggle off. So, if I'm initially only loading the countriy level, I need a way to be able to programatically set the checkbox to tri-state checked. If I can't it means I have to load the lower levels immediately and I'm back to my initial problem.
3) How do you programatically retrieve a branch of the hierarchy? Since I need to be able to bind the checkbox states when the "branch" of the tree is requested how do you do this? Is this a "nodeBy" method scenario?
4) I need to get the checkboxes that are checked upon submission of the form. Isn't this just delaying the need for load? Basically, wouldn't I have to do a full load of the tree upon submission to retrieve all of the checkboxes anyway?
Or is there a way to load the tree and bind the checkboxes in one step where even if they aren't rendered until loadOnDemand that the state internally is still checked, just the DOM node isn't created?
Thanks
I hope I have understood your scenario:
Basically you do not have top level nodes checked, just middle/bottom level nodes in such states, which are initially not loaded from the server. You do still want the parent node to appear partially checked before the load. - let me know if this isn't it.
Basically the partially checked state cannot be set programmatically because it is the "middle" state in a tri-state indicating that some of the child nodes of the parent are checked, but there are others that are not. The partial state is set internally upon changing the checkstate of a child node (in your case the child nodes are not yet loaded and I see where the problem is coming from).
If the parent node is checked and you request its children, you would not need to call any methods to check them, because they would be rendered checked, however if you don't have the parent node checked, but you want to render some children with checked state, then you can write a custom method to check the children and the checkstate would internally cascade such that it partially checks their parent.
You can retrieve a parent node by calling nodeByPath: function (nodePath) providing the path of the node (you can also retrieve the node from the expanding event). Then going down this branch you can retrieve the child nodes by calling the children: function (parent) method. Note that the first method retrieves a jQuery element, while the second one retrieves an array of node objects (the jQuery element of each is the element property).
The checkedNodes: function () method retrieves all the checked nodes from the client. This does not perform any submission of your form. The jQuery tree, as well as the other jQuery controls are purely client, so they do not have a state in the way ASP.NET for example would. This is also the reason why you cannot have checkstate indicated on the server with a property or any other way. That also means that when you have loadOnDemand, there is no internal state of the nodes before they have been loaded. In fact there is no data on the client for those nodes, until they have been loaded. The data retrieval is performed once the client tries to expand a node.
Let me know if my explanation makes sense and how I can help you further!
Yes. I'm playing with things a bit more. I have an idea I'm going to run with and I'll report back.
Hi again,
I tried to reproduce the performance issue. I made the following sample:
<div id="tree3"></div>
var ul = $('<ul></ul>').appendTo($('#tree3')), markup = ''; for (var i = 0; i < 3; i++) { markup += '<li>Node Text<ul>'; for (var j = 0; j < 50; j++) { markup += '<li>Node Text<ul>'; for (var k = 0; k < 51; k++) { markup += '<li>Node Text</li>'; } markup += '</ul></li>'; } markup += '</ul></li>'; } ul.html(markup); $('#tree3').igTree({ checkboxMode: 'triState' });
The checkboxes did not show any performance slowdown for me. I check them and they instantly cascade down. I tested this against IE9/Firefox13/Chrome 19/Maxthon 3.4.1.
Maybe you're using a different browser, if that's the case let me know which one. This sample actually has 7650 nodes.
Thank you for your patience!
The issue is not with manually checking the checkboxes on the UI. That works fine.
It is with programatically setting the checked boxes on page load.
We load the tree into our page and a set of checkboxes need to be checked based on user selection.
This is an Edit page where on the create page prior the user selected a set of checkboxes in the tree so on Edit we are loading their selections.
US => Region => District => Store
A common example for us is we have the entire US node selected except a half dozen checkboxes all the way down at the storelevel of the tree. This means that the top node should be a partial check, the second level (of which there are usually 20 entries) should all be full checked except one, the third level should all be full checked except one, and the store level is all checked except the six stores in quesiton.
Your example would have to be extended to next get a set of the nodes in your tree and check them upon page load. Mind you this also involves two server calls as well, one to get the tree, and another to get the selected items.
Also, the target browser in this case is IE8. Not my choice unfortunately. The logic I currently have works well enough in Chrome and Firefox. There's still a lag of perhaps 1-2 seconds but it's nothing major. IE 8 however throws the dreaded long running script error twice before completing.
I'm trying to move as much processing as possible to the server as I know IE8 javascript engine is, to be nice, horrific.
I hope this gives you a better idea of what we're attempting to do.
Hello CharGuilette,
Thank you for your reply.
Please feel free to contact us with any updates and additional questions.
Thanks for the quick followup.
I'll give this a go later today and post back the results.
I guess I see exactly what the issue is. Let's try and trick the JS engine of the IE8. Do the following after the tree is rendered:
var tree = $('#treeID').data('igTree'); var checkbox = $('#treeID').find('span[data-role=checkbox]'); var checkIcon = checkbox.children('span'); checkbox.attr('data-chk', 'on'); checkIcon.removeClass(tree.css.checkboxOff).addClass(tree.css.checkboxOn);
This would change all the checkboxes to being checked. Then call toggleCheckstate only on the nodes you need unchecked.
Let me know if this improves performance or we still at hitting the wall?