Hello,
I'm trying to write a custom filtering for the RadDropDownTree however i'm faced some performance issues. Here is my JS code :
function
OnHierarchicalClientLoad_<%= ClientID %>(sender, eventArgs) {
var
dropDownTree = $find(
"<%= RadDropDownTree.ClientID %>"
);
var
typingTimer;
//timer identifier
var
doneTypingInterval = 1000;
//time in ms, 5 second for example
$input = $(
"<input type=\"search\" class=\"search-field\" name=\"the_search\">"
);
$input.on(
'keyup'
,
function
() {
clearTimeout(typingTimer);
typingTimer = setTimeout(
function
() {
$value = $input.val();
var
tree = dropDownTree.get_embeddedTree();
tree.trackChanges();
var
nodes = tree.get_nodes();
for
(
var
i = 0; i < nodes.get_count() ; i++) {
var
node = nodes.getNode(i);
SetHierarchicalComboBoxItemVisibility(node, $value);
}
tree.commitChanges();
}, doneTypingInterval);
});
$input.on(
'keydown'
,
function
() {
clearTimeout(typingTimer);
});
$(
"#<%= RadDropDownTree.ClientID %> .rddtHeader"
).append($input);
}
function
SetHierarchicalComboBoxItemVisibility(node, filter) {
var
isVisible =
false
;
var
allNodes = node.get_allNodes();
for
(
var
i = 0; i < allNodes.length; i++) {
var
childNode = allNodes[i];
isVisible = SetHierarchicalComboBoxItemVisibility(childNode, filter);
}
isVisible = (isVisible || filter ==
""
|| node.get_text().toLowerCase().indexOf(filter.toLowerCase()) != -1);
node.get_element().style.display = isVisible ?
""
:
"none"
;
//Workaround
//node.set_visible(isVisible); //performance too slow
return
isVisible;
}
As you can see I used a workaround because the set_visible() function is too slow when there is a bit amount of nodes (some thousands). It seems that it use some functions that do some css stuffs on sibling node as ensureAppearance().
So I have two questions :
- Is there a way to optimise the use of set_visible() function on a huge amount of nodes ?
- Else, is my workaround may cause problems?
Thank you,
11 Answers, 1 is accepted
As you had well observed, the set_visible method ensures that not only the current node will be hidden, but its child nodes as well. Also, it ensures that if there are any child nodes to hide - the toggle element of the parent node will also be hidden.
This is why, it requires more time. It's up to you and your scenario to evaluate whether this approach with the styling is applicable. In other words, if you don't have an hierarchical structure of the nodes - it will be. Otherwise, I suggest you to use the set_visible method, which is tested and we can grantee that no unexpected behavior will be caused by its usage.
On a side note, please keep in mind that such customization are not supported and once implemented they become developers responsibility.
Regards,
Nencho
Telerik by Progress
Hello Nencho,
I understand your suggestion about I should use the set_visible method and it's precisly what I wanted to do. However, due to performance issues I cannot ignore, I need to find another solution. Please understand I cannot let the user waits a couple of secs (with browser frozen) each time he makes a search....
Plus, I also noticed that RadDropDownTreeNode set_visible is not the only client function which may be slow. Each time, I use on client side set_enabled on RadDropDownTree it spends even more time. For about 10 RadDropDownTrees with some hundred of node inside, it spends about 20 seconds to makes them disabled. I thought that RadDropDownTree set_enabled function just avoids the dropdown to open but it seems that it also set all the tree node enable property...
Please try to understand that it's not a possible solution for us to let the user browser freeze in this way...
Thanks,
We have reviewed your implementation and we were unable to find part of it that would possibly cause major issues with the control functionality. However, note that if yo you have hierarchical data and you hide a parent node that does not meet the filtering string, but you have a child node that does meet the filtering criteria, you wont be able to view that child node too.
In order to show the parent nodes of visible nodes, I would suggest you to introduce ​isInnerVisible variable to your ​SetHierarchicalComboBoxItemVisibility() function:
function
SetHierarchicalComboBoxItemVisibility(node, filter) {
var
isVisible =
false
;
var
isInnerVisible =
false
;
var
allNodes = node.get_allNodes();
for
(
var
i = 0; i < allNodes.length; i++) {
var
childNode = allNodes[i];
isVisible = SetHierarchicalComboBoxItemVisibility(childNode, filter);
isInnerVisible = isInnerVisible || isVisible;
}
isVisible = (isVisible || isInnerVisible || filter ==
""
|| node.get_text().toLowerCase().indexOf(filter.toLowerCase()) != -1);
node.get_element().style.display = isVisible ?
""
:
"none"
;
return
isVisible;
}
As my colleague Nencho pointed out, you should keep in mind that this is a customization of the control functionality.
Regards,
Veselin Tsvetanov
Telerik by Progress
Hi Veselin,
Indeed, I noticed and fixed that issue in my code a couple of days ago. My code is faster, however it does not hide the dropdown icon in case there is no child item.
Moreover, is there a way to make the radDropDownTree.set_enabled() faster? As I said before, when there is some raddropdowntrees in the same page, it spends a lot of time to make them disabled.
Regards,
As you correctly noticed, the custom implementation discussed does not cover all the edge cases, that the built-in functionality does. Performing all the needed checks is one of the reasons for the slower performance of the set_visivble() method.
Concerning the set_enabled() issue, I have created a sample page, implementing a scenario with 10 RadDropDownLists, each with 500 items. By clicking on the "Disable" button the user could disable all of them. Running it locally on Chrome, this takes less than a second to do that. Could you, please modify this sample, so it reproduces the problem observed and send it back to us?
Regards,
Veselin Tsvetanov
Telerik by Progress
Hello Veselin,
Indeed, when I execute your sample page the set_enabled function is fast. However, in your project, there is just one level in each RadDropDownTree. I updated your code to build tree levels on each treeview . Plus I added the Checkbox feature which increase a lot the execution time of the set_enabled function. These two modifications make your page closer to my needs. Please update your project with the following code and let me know if you are able to reproduce the problem :
protected void Page_Load(object sender, EventArgs e)
{
DataTable data = new DataTable();
data.Columns.Add("value");
data.Columns.Add("text");
data.Columns.Add("ID");
data.Columns.Add("ParentID");
int id = 0;
List<
DataRow
> rootRow = new List<
DataRow
>();
for (int j = 0; j <
5
; j++)
{
DataRow
currentRow
=
data
.NewRow();
currentRow["text"] = "Country " + j;
currentRow["value"] = "Value " + j;
currentRow["ID"] = id;
rootRow.Add(currentRow);
id++;
}
List<DataRow> nodeRow = new List<
DataRow
>();
foreach (var row in rootRow)
{
data.Rows.Add(row);
for (int i = 0; i < 10; i++) {
DataRow currentRow = data.NewRow();
currentRow["text"] = "Country " + row["ID"] + i;
currentRow["value"] = "Value " + row["ID"] + i;
currentRow["ID"] = id;
currentRow["ParentID"] = row["ID"];
nodeRow.Add(currentRow);
id++;
}
}
foreach (var row in nodeRow)
{
data.Rows.Add(row);
for (int i = 0; i < 10; i++)
{
DataRow currentRow = data.NewRow();
currentRow["text"] = "Country " + row["ID"] + i;
currentRow["value"] = "Value " + row["ID"] + i;
currentRow["ID"] = id;
currentRow["ParentID"] = row["ID"];
data.Rows.Add(currentRow);
id++;
}
}
for (int i = 1; i <= 10; i++)
{
var dropDownTreeID = "RadDropDownTree" + i;
var tree = (RadDropDownTree)Page.FindControl(dropDownTreeID);
tree.CheckBoxes = DropDownTreeCheckBoxes.SingleCheck;
tree.DataTextField = "text";
tree.DataValueField = "value";
tree.DataFieldID = "ID";
tree.DataFieldParentID = "ParentID";
tree.DataSource = data;
tree.DataBind();
}
}
I have tested the same page with your suggested implementation (attached). In Crome 54 browser the 10 RadDropDownLists are disabled for around 200 ms. You could see running the test here.
Regards,
Veselin Tsvetanov
Telerik by Progress
Hello Veselin,
I forgot to precise that I use IE 11 for my tests. Could you please run your project on this browser and tell me if you have got the same results?
Thank you,
Thank you for the additional information provided. Based on that I was able to reproduce the performance issue both in IE 11 and Edge.
After a careful review of the control functionality, we can confirm that the discussed is a performance issue. Therefore, I have included it in our backlog. I have also created a bug item in our Feedback portal, where you could track the bug status.
As a token of gratitude for helping us to isolate the issue, I have updated your Telerik points.
Going back to the discussed example, I could suggest you the following change to the disable function of the DropDownTrees:
for
(
var
i = 1; i <= 10; i++) {
var
tree = $find(
'RadDropDownTree'
+ i);
// This disables the Tree
tree._enabled =
false
;
var
$element = $telerik.$(tree.get_element),
$innerDiv = $element.find(
'.rddtInner'
),
$clearButton = $element.find(
'.rddtClearButton'
);
// This adds the needed attributes and classes on the Tree elemnts,
// so they appear disabled on the screen
$innerDiv.addClass(
'rddtDisabled'
);
$clearButton.attr(
'disabled'
,
'disabled'
);
tree.closeDropDown();
tree._toggleAttribute(
tree
._element,
true
,
"tabindex"
,
null
);
}
Attached you will find a modified sample page, implementing the above.
Regards,
Veselin Tsvetanov
Telerik by Progress
Hi Veselin,
Thank you for the workaround. Performance is much better with this.
I saw the bug created on your Feedback portal. However you didn't talk about set_visible() function on RadDropDownTreeNode with is also too slow on IE when RadDropDownTree contains a lot of nodes. Please don't forget that it's the first problem I described on this thread and I still not have a good workaround to deal with it.
Thanks,
The set_visible() functionality of the RadDropDownTree requires considerable DOM manipulations, in order to guarantee correct rendering of all nodes, their status, the expanding capabilities and so on. Therefore, this functionality heavily relies on the browser's JavaScript engine to process the manipulations fast. In consequence, hiding all the root nodes in a DropDownTree with 500 root nodes may require around 250 ms on Google Chrome, while the same operation may require around 5 seconds in IE.
The main difference with the set_enabled() scenario is the fact, that when disabling the entire DropDownTree, we do not need to disable the nodes one by one (which causes the performance issue in our internal implementation), while here, we have to iterate over all nodes and make sure those that remain visible render correctly. Therefore, the set_visible() performance issue is considered to be an IE browser limitation and not a bug in the control's functionality.
Regards,
Veselin Tsvetanov
Telerik by Progress