RadDropDownTree custom filtering

12 posts, 0 answers
  1. Jerome MAILLEY
    Jerome MAILLEY avatar
    17 posts
    Member since:
    Jul 2009

    Posted 18 Oct Link to this post

    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,

  2. Nencho
    Admin
    Nencho avatar
    1457 posts

    Posted 21 Oct Link to this post

    Hello Jerome,

    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
    Check out the new UI for ASP.NET Core, the most complete UI suite for ASP.NET Core development on the market, with 60+ tried-and-tested widgets, based on Kendo UI.
  3. UI for ASP.NET Ajax is Ready for VS 2017
  4. Jerome MAILLEY
    Jerome MAILLEY avatar
    17 posts
    Member since:
    Jul 2009

    Posted 25 Oct in reply to Nencho Link to this post

    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,

  5. Veselin Tsvetanov
    Admin
    Veselin Tsvetanov avatar
    281 posts

    Posted 28 Oct Link to this post

    Hi Jerome,

    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
    Check out the new UI for ASP.NET Core, the most complete UI suite for ASP.NET Core development on the market, with 60+ tried-and-tested widgets, based on Kendo UI.
  6. Jerome MAILLEY
    Jerome MAILLEY avatar
    17 posts
    Member since:
    Jul 2009

    Posted 28 Oct in reply to Veselin Tsvetanov Link to this post

    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,

  7. Veselin Tsvetanov
    Admin
    Veselin Tsvetanov avatar
    281 posts

    Posted 01 Nov Link to this post

    Hello Jerome,

    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
    Check out the new UI for ASP.NET Core, the most complete UI suite for ASP.NET Core development on the market, with 60+ tried-and-tested widgets, based on Kendo UI.
  8. Jerome MAILLEY
    Jerome MAILLEY avatar
    17 posts
    Member since:
    Jul 2009

    Posted 07 Nov in reply to Veselin Tsvetanov Link to this post

    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();
     
                }
     
            }

     

  9. Veselin Tsvetanov
    Admin
    Veselin Tsvetanov avatar
    281 posts

    Posted 09 Nov Link to this post

    Hello Jerome,

    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
    Check out the new UI for ASP.NET Core, the most complete UI suite for ASP.NET Core development on the market, with 60+ tried-and-tested widgets, based on Kendo UI.
  10. Jerome MAILLEY
    Jerome MAILLEY avatar
    17 posts
    Member since:
    Jul 2009

    Posted 09 Nov Link to this post

    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,

  11. Veselin Tsvetanov
    Admin
    Veselin Tsvetanov avatar
    281 posts

    Posted 10 Nov Link to this post

    Hi Jerome,

    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
    Check out the new UI for ASP.NET Core, the most complete UI suite for ASP.NET Core development on the market, with 60+ tried-and-tested widgets, based on Kendo UI.
  12. Jerome MAILLEY
    Jerome MAILLEY avatar
    17 posts
    Member since:
    Jul 2009

    Posted 18 Nov in reply to Veselin Tsvetanov Link to this post

    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,

  13. Veselin Tsvetanov
    Admin
    Veselin Tsvetanov avatar
    281 posts

    Posted 22 Nov Link to this post

    Hello Jerome,

    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
    Telerik UI for ASP.NET AJAX is ready for Visual Studio 2017 RC! Learn more.
Back to Top
UI for ASP.NET Ajax is Ready for VS 2017