TreeView Filtering

12 posts, 0 answers
  1. Telerik Admin
    Telerik Admin avatar
    1679 posts
    Member since:
    Oct 2004

    Posted 25 Jan 2012 Link to this post

    Requirements

    RadControls version Q3 2010 or later
    .NET version 4
    Visual Studio version 2010
    programming language C#, Javascript
    browser support

    all browsers supported by RadControls

     
    PROJECT DESCRIPTION
    This project shows how to filter the Treeview, so that only the nodes that contain the text entered through the TextBox remain visible.

    ASPX:
    <body>
        <form id="form1" runat="server">
            <asp:ScriptManager ID="ScriptManager1" runat="server" />
            <script type="text/javascript">
     
                var timer = null;
     
                function clientLoad(sender) {
                    $telerik.$(".riTextBox", sender.get_element().parentNode).bind("keydown", valueChanging);
                }
     
                function valueChanging(sender, args) {
                    if (timer) {
                        clearTimeout(timer);
                    }
     
                    timer = setTimeout(function () {
                        var tree = $find("<%= RadTreeView1.ClientID %>");
                    var textbox = $find("<%= RadTextBox1.ClientID %>");
                    var searchString = textbox.get_element().value;
     
                    for (var i = 0; i < tree.get_nodes().get_count() ; i++) {
                        findNodes(tree.get_nodes().getNode(i), searchString);
                    }
                }, 200);
            }
     
            function findNodes(node, searchString) {
                node.set_expanded(true);
     
                var hasFoundChildren = false;
                for (var i = 0; i < node.get_nodes().get_count() ; i++) {
                    hasFoundChildren = findNodes(node.get_nodes().getNode(i), searchString) || hasFoundChildren;
                }
     
                if (hasFoundChildren || node.get_text().toLowerCase().indexOf(searchString.toLowerCase()) != -1) {
                    node.set_visible(true);
                    return true;
                }
                else {
                    node.set_visible(false);
                    return false;
                }
            }
     
            </script>
            <div>
     
                <telerik:RadTextBox ClientEvents-OnLoad="clientLoad" ID="RadTextBox1" runat="server" />
                <telerik:RadTreeView ID="RadTreeView1" runat="server">
                    <ExpandAnimation Type="None" />
                    <CollapseAnimation Type="None" />
                </telerik:RadTreeView>
     
            </div>
        </form>
    </body>

    C#:
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            RadTreeView1.LoadContentFile("~/Xml/Tree.xml");
        }
    }

    Tree.xml:
    <?xml version="1.0" encoding="utf-8" ?>
    <Tree>
        <Node Text="Desktop" Expanded="True" ToolTip="Desktop">
            <Node Text="Administrator" Expanded="True">
                <Node Text="AppData" >
                    <Node Text="Microsoft" />
                </Node>
                <Node Text="Contacts" />
                <Node Text="Downloads" />
                <Node Text="Documents" />
                <Node Text="Favorites" >
                    <Node Text="Links" />
                </Node>
                <Node Text="Music" />
                <Node Text="Pictures" />
                <Node Text="Saved Games" />
                <Node Text="Searches" >
                    <Node Text="History" />
                </Node>
                <Node Text="Videos" />
            </Node>
            <Node Text="Computer" ToolTip="My Computer" Expanded="True" >
                <Node Text="WebServer (\\10.0.0.80) (W:)" />
                <Node Text="Local Disk (C:)" Expanded="True" >
                    <Node Text="inetpub" Expanded="True">
                        <Node Text="AdminScripts"></Node>
                    </Node>
                </Node>
                <Node Text="Local Disk (D:)" Expanded="True" >
                    <Node Text="Movies" />
                    <Node Text="Music" />
                    <Node Text="Games" />
                </Node>
            </Node>
        </Node>
    </Tree>
  2. Fredrik
    Fredrik avatar
    6 posts
    Member since:
    Nov 2012

    Posted 01 Aug 2013 Link to this post


    This project is exactly what i need.
    BUT, the events are not triggering correct.
    it isnt triggered on keypress, sometimes you have to leave the textbox to make it work.
    Sometimes i have to reload the page to get all nodes back.

    please post working examples or inform of the fact that it isnt working.
  3. Bozhidar
    Admin
    Bozhidar avatar
    1101 posts

    Posted 05 Aug 2013 Link to this post

    Hello Fredrik,

    Thank you for reporting this to us.

    To fix the issue please change the following line:
    var searchString = textbox.get_value();
    to:
    var searchString = textbox.get_element().value;

    We will update the CodeLibrary article to reflect this change. I've also updated your telerik points.
     

    All the best,
    Bozhidar
    the Telerik team
    If you want to get updates on new releases, tips and tricks and sneak peeks at our product labs directly from the developers working on the RadControls for ASP.NET AJAX, subscribe to their blog feed now
  4. Fredrik
    Fredrik avatar
    6 posts
    Member since:
    Nov 2012

    Posted 05 Aug 2013 Link to this post

    Ok.
    Thanks.

    I ended up rewriting most of the code and im posting it here if anyone is interrested.
    My final result looks like this and works good.

    This filters on keypress and restore the tree when clearing the filter textbox.
    It also expands and selects all nodes that are a match.
    Its not fancy and Im sure it can be rewritten to be more effective.


    var selectednode;
    function valueChanging(sender, args) {
    var tree = $find("<%= RadTreeView_Organisation.ClientID %>");
    var textbox = document.getElementById("<%= Filter.ClientID %>");
    //alert(textbox.value);
    var searchString = textbox.value;
    if (searchString == "") {
    ClearFilter();
    }
    else {
    var allNodes = tree.get_allNodes();
    var index;
    for (index = 0; index < allNodes.length; index++) {
    var node = allNodes[index];
    node.set_selected(false);
    }

    for (index = 0; index < allNodes.length; index++) {
    var node = allNodes[index];
    if (node.get_expanded)
    node.collapse();
    }

    LoopIt(searchString, tree, textbox);
    expandit();
    }
    return false;
    }
    function ClearFilter() {
    var tree = $find("<%= RadTreeView_Organisation.ClientID %>");
    var textbox = $find("<%= Filter.ClientID %>");
    var allNodes = tree.get_allNodes();
    for (index = 0; index < allNodes.length; index++) {
    var node = allNodes[index];
    node.set_visible(true);
    node.set_selected(false);
    if (node.get_expanded)
    node.collapse();
    }
    setTimeout(allNodes[0].expand(), 450); 
    return false;
    }
    function LoopIt(searchString, tree, textbox) {
    var allNodes = tree.get_allNodes();
    allNodes[0].expand;
    for (var i = 0; i < tree.get_nodes().get_count() ; i++) {
    findNodes(tree.get_nodes().getNode(i), searchString);
    }
    }
    function expandit() {
    if (selectednode != null) {
    selectednode = selectednode.get_parent();

    while (selectednode != null) {
    // selectednode.set_selected(true);
    if (selectednode.expand) {
    selectednode.expand();
    }

    selectednode = selectednode.get_parent();
    }
    }
    }

    function findNodes(node, searchString) {
    var hasFoundChildren = false;

    if (hasFoundChildren || node.get_text().toLowerCase().indexOf(searchString.toLowerCase()) != -1) {
    node.set_selected(true);
    }

    for (var i = 0; i < node.get_nodes().get_count() ; i++) {
    hasFoundChildren = findNodes(node.get_nodes().getNode(i), searchString) || hasFoundChildren;
    }

    if (hasFoundChildren || node.get_text().toLowerCase().indexOf(searchString.toLowerCase()) != -1) {
    node.set_visible(true);

    node.expand();
    if (node.get_text().toLowerCase().indexOf(searchString.toLowerCase()) != -1) {
    node.set_selected(true);
    for (var i = 0; i < node.get_nodes().get_count() ; i++) {
    DisplayChildren(node);
    //node.get_nodes().getNode(i).set_visible(true);
    }
    }
    return true;
    }
    else {
    node.set_visible(false);
    return false;
    }
    }

    function DisplayChildren(node) {
    for (var ee = 0; ee < node.get_nodes().get_count() ; ee++) {
    node.get_nodes().getNode(ee).set_visible(true);
    //node.get_nodes().getNode(ee).set_expanded(true);
    DisplayChildren(node.get_nodes().getNode(ee));
    }
    }
    //end Treeviewfilter

  5. Fredrik
    Fredrik avatar
    6 posts
    Member since:
    Nov 2012

    Posted 05 Aug 2013 Link to this post

    Btw.
    Thanks Bozhidar!

     And...
    $find(" was too slow so i had to use document.getElement to get it to work.
    And to make the script work i hade to use the timeouts... not very neat but it works.
  6. Dayre-Musetti
    Dayre-Musetti avatar
    3 posts
    Member since:
    Apr 2012

    Posted 25 Sep 2013 Link to this post

    Hi,

    This code is exactly what I needed to be able to filter thru 300 nodes. Unfortunatly our organisation is stuck on IE8 (yes, I know...) and we have this error message : "A script on this page is causing Internet Explorer to run slowly".

    Any sugestion to boost this code?

    Thank's
  7. Fredrik
    Fredrik avatar
    6 posts
    Member since:
    Nov 2012

    Posted 25 Sep 2013 Link to this post

    Hi,

    Try to adjust/remove the timeouts.
    Otherwise i have no clue... i havent tweaked this script any more since i posted the solution.
    If you come up with something be sure to post and share.
  8. Dayre-Musetti
    Dayre-Musetti avatar
    3 posts
    Member since:
    Apr 2012

    Posted 26 Sep 2013 Link to this post

    Hi Fredik,

    Thank's for answering.

    I searched on Google and found an interesting article on this issue : http://www.sitepoint.com/multi-threading-javascript/

    I refactor (and customize for my needs) your code like this:

    function changeFiltre(sender, args) {
                var i = 0, busy = false;
                var tree = $find("<%= twBalise.ClientID %>");
                var textbox = $find("<%= txtFiltreBaliseThread.ClientID %>");
                var searchString = textbox.get_textBoxValue()
                var allNodes = tree.get_allNodes();
     
                var processor = setInterval(function () {
                    if (!busy) {
                         
                        busy = true;
     
                         
                            var node = allNodes[i];
                            process(node, searchString);
     
                            if (++i == allNodes.length) {
                                clearInterval(processor);
     
                            }
                         
     
     
     
     
                        busy = false;
                    }
     
                }, 1);
            }
     
            function process(node, searchString) {
     
                 
     
                    if (node.get_text().toLowerCase().indexOf(searchString.toLowerCase()) != -1) {
                        node.set_visible(true);
                    }
                    else {
                        node.set_visible(false);
                    }
            }

    This code run a bit slower but avoid the stupid  "A script on this page is causing Internet Explorer to run slowly" message.

    I hope this trick will help someone.

    Jean-François

  9. Jairo
    Jairo avatar
    5 posts
    Member since:
    Dec 2014

    Posted 28 Jan 2015 in reply to Telerik Admin Link to this post

    Hi,
    I know this is an old post, but I recently began to work with Telerik controls for Ajax and I've encountered this post useful for what I need. Nontheless, this code doesn't work in Chrome. When I implemented this code in my solution, it works perfectly in IE and even Firefox, but in Chrome it only filter the root nodes leaving the treeview blank most of the time because it doesn't find anything apparently.

    I tested RadDropDownTree and it doesn't have this problem at ell and even it has more features in the searchbox than this code but, this control doesn't suit my needs. As this is a dropdown list (or tree) it gets collapsed when a node is selected and it overlaps any control that is below the dropdown object what is its normal behaviour.

    I need the treeview to be fixed inside a container with an specific size being always visible with the searchbox to provide filter capabilities. In the attached images, I was able to reproduce the problem with your provided sample code, when I type "mi" looking for the node "Microsoft" inside the node "AppData", it shows correctly in IE, but if you try the same in Chrome, it isn't found. Is there any workaround for this?
    Thanks in advance.
    Jairo Ramirez
  10. Bozhidar
    Admin
    Bozhidar avatar
    1101 posts

    Posted 29 Jan 2015 Link to this post

    Hi,

    I was able to reproduce the issue and it turns out it's related to the animations which are executed upon expanding and collapsing of nodes. In order to fix the issue just disable the animation of the TreeView:
    <telerik:RadTreeView ID="RadTreeView1" runat="server">
        <ExpandAnimation Type="None" />
        <CollapseAnimation Type="None" />
    </telerik:RadTreeView>

    We will also update the CodeLibrary accordingly.

    Regards,
    Bozhidar
    Telerik
     

    Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

     
  11. Jairo
    Jairo avatar
    5 posts
    Member since:
    Dec 2014

    Posted 29 Jan 2015 in reply to Bozhidar Link to this post

    Hi Bozhidar,
    Effectively I made the change and it worked. It's a shame that I have to get rid of the animations which makes the control to look visually better to users. As a workaround, I've disabled the animations only if the browser is Chrome as it works well in FF and IE (code below in c# on page load event). It seems Ajax controls have issues with Chrome as I'm also having issues with RadPanelBar in Chrome but it will be another post. Thank you very much for your help.
    if (Request.Browser.Type.ToUpper().Contains("CHROME"))
           {
               RadTreeView1.CollapseAnimation.Type = AnimationType.None;
               RadTreeView1.ExpandAnimation.Type = AnimationType.None;
           }
  12. Ashraf Sabry
    Ashraf Sabry avatar
    88 posts
    Member since:
    Jan 2011

    Posted 05 Jul 2015 Link to this post

    This code worked for me very well. I used it to combine both TreeView and jQueryUI autocomplete to create an autocomplete tree widget. Thanks for sharing this.

     But it should be noted that animations must be disabled for the tree for this code to work, because getting a node text while animating returns an empty string (this seems to be a bug).

Back to Top