skip to Main Content
        $.fn.extend({

      treed: function (o) {

        var openedClass = 'fa-minus-circle';
        var closedClass = 'fa-plus-circle';

        if (typeof o != 'undefined'){
          if (typeof o.openedClass != 'undefined'){
            openedClass = o.openedClass;
          }
          if (typeof o.closedClass != 'undefined'){
            closedClass = o.closedClass;
          }
        }

        //initialize each of the top levels

        var tree = $(this);

        tree.addClass("tree");

        tree.find('li').has("ul").each(function () {

            var branch = $(this); //li with children ul
            branch.prepend("<i class='indicator fas " + closedClass + "'></i>");
            branch.addClass('branch');

            // declare a flag to toggle

            let flag = false;

            branch.on('click', function (e) {

                if (this == e.target) {
                    // toggle on click

                    flag = !flag;
                    var icon = $(this).children('i:first');
                    icon.toggleClass(openedClass + " " + closedClass); 

                    // show loader only when its opened, and collpase once toggled
      
                    if(flag) {
                      $(this).append("<div class='loading'><span class='fa fa-spinner fa-spin'</span></div>"); 
                      setTimeout(()=>{
                        $(this).find('.loading').remove();
                        $(this).children().children().slideToggle(400);
                      }, 400)
                    } else {
                      $(this).children().children().slideToggle(400);
                    }
                }

            });

            branch.children().children().toggle();

        });

        //fire event from the dynamically added icon

        tree.find('.branch .indicator').each(function(){

          $(this).on('click', function () {
              $(this).closest('li').click();
          });

        });

        //fire event to open branch if the li contains an anchor instead of text

        tree.find('.branch>a').each(function () {

            $(this).on('click', function (e) {
                $(this).closest('li').click();
                e.preventDefault();
            });

        });

        //fire event to open branch if the li contains a button instead of text

        tree.find('.branch>button').each(function () {

            $(this).on('click', function (e) {
                $(this).closest('li').click();
                e.preventDefault();
            });

        });

        //adding "openAll" and "closeAll" functions to the tree

        tree.openAll = function(){
          tree.find('li').has("ul").each(function () {

            //finding if opened or closed from icon
            //TODO: find a simpler way, like a property set on "branch"?
            var branch = $(this); //li with children ul
            var icon = branch.children('i:first');

            //opening all closed ones
            if(icon.hasClass(closedClass)){
              branch.click();
            }
          });
        };
        tree.closeAll = function(){
          tree.find('li').has("ul").each(function () {

            //finding if opened or closed from icon
            //TODO: find a simpler way, like a property set on "branch"?
            var branch = $(this); //li with children ul
            var icon = branch.children('i:first');

            //opening all closed ones
            if(icon.hasClass(openedClass)){
              branch.click();
            }
          });      
        };

        //return the tree so we can store it in a var and call the functions

        return tree;

      }

    });

        

    //Initialization of treeviews

    //$('#tree1').treed();

    var tree2 = $('#tree2').treed({openedClass:'fa-folder-open', closedClass:'fa-folder'});

    //code for the buttons
    $('#openall').on('click', function(){
      tree2.openAll();
    });
    $('#closeall').on('click', function(){
      tree2.closeAll();
    });
$('#searchInput').on('keyup', function() {
  var searchText = $(this).val().toLowerCase();
  
  $('#tree2 li').each(function() {
    var name = $(this).text().toLowerCase();
    
    if (name.indexOf(searchText) !== -1) {
      $(this).show();

    }
  });
});
        .intro {
  background-color: yellow;
}
    .tree {

      overflow-y: auto;

    }

    .branch {

      white-space: nowrap;

    }

    .tree, .tree ul {

          margin:0;

          padding:0;

          list-style:none;

          margin-left:10px;

        }

        .tree ul {

          margin-left:1em;

          position:relative

        }

        .tree ul ul {

          margin-left:.5em

        }

        .tree ul:before {

          content:"";

          display:block;

          width:0;

          position:absolute;

          top:0;

          bottom:0;

          left:0;

          border-left:1px solid

        }

        .tree li {

          margin:0;

          padding:0 1em;

          line-height:2em;

          color:#369;

          font-weight:700;

          position:relative;

        }

        .tree ul li:before {

          content:"";

          display:block;

          width:10px;

          height:0;

          border-top:1px solid;

          margin-top:-1px;

          position:absolute;

          top:1em;

          left:0

        }

        .tree ul li:last-child:before {

          background:#fff;

          height:auto;

          top:1em;

          bottom:0

        }

        .indicator {

          margin-right:5px;

        }

        .tree li a {

          text-decoration: none;

          color:#369;

        }

        .tree li button, .tree li button:active, .tree li button:focus {

          text-decoration: none;

          color:#369;

          border:none;

          background:transparent;

          margin:0px 0px 0px 0px;

          padding:0px 0px 0px 0px;

          outline: 0;

        }

        .loading {

          font-style: italic;

        }

    .timeline {

      border-left: 1px solid hsl(0, 0%, 90%);

      position: relative;

      list-style: none;

    }

    .timeline .timeline-item {

      position: relative;

    }

    .timeline .timeline-item:after {

      position: absolute;

      display: block;

      top: 0;

    }

    .timeline .timeline-item:after {

      background-color: hsl(0, 0%, 90%);

      left: -38px;

      border-radius: 50%;

      height: 11px;

      width: 11px;

      content: "";

    }
        <section class="content">

      <div class="container-fluid">

      <div class="card">

        <div class="card-body">              

          <div class="row">

            <div class="col-md-4">
<div class="input-group mb-3">
  <span class="input-group-text" id="basic-addon1"> <i class="fa fa-search"></i></span>
  <input type="text" class="form-control" id="searchInput"  aria-label="Username" aria-describedby="basic-addon1">
</div>
<br>
            

    <button type="button" id ="openall"class="btn btn-warning" id ">open All</button>
    <button type="button" id="closeall" class="btn btn-info">closeAll</button>
<br>
<ul id="tree2">
              <li>

              <a href="#">TECH</a>

              <ul>

                <li>Company Maintenance</li>

                <li>

                  Employees

                  <ul>

                    <li>

                    Reports

                    <ul>

                      <li>Report1

                      <ul>

                      <li>Report1

                      <ul>

                      <li>Report1

                      <ul>

                      <li>Report1</li>

                      <li>Report2</li>

                      <li>Report3</li>

                    </ul>

                      </li>

                      <li>Report2</li>

                      <li>Report3</li>

                    </ul>

                      </li>

                      <li>Report2</li>

                      <li>Report3</li>

                    </ul>

                      </li>

                      <li>Report2</li>

                      <li>Report3</li>

                    </ul>

                    </li>

                    <li>Employee Maint.</li>

                  </ul>

                </li>

                <li>Human Resources</li>

              </ul>

              </li>

                 </ul>

          </div>        

          </div>

       </div>

      <div class="card-footer text-body-secondary">

    </div> 

    </div>  <!-- /.container-fluid -->

       </section>

                        

    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.rtl.min.css">

       <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet">

    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.0/css/all.css" integrity="sha384-lZN37f5QGtY3VHgisS14W3ExzMWZxybE1SJSEsQp9S+oqd12jhcu+A56Ebc1zFSJ" crossorigin="anonymous">

    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->


    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm" crossorigin="anonymous"></script>

    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script>

I have this TreeView and I want to filter its items and display the item whose name is entered in the input above this TreeView. I want the searched item to be displayed in a different format (background – color = yellow ) and all the items in the TreeView to be expanded. If the item is not found, all the menu items should be collapsed and a notification message should be displayed indicating that the desired item is not found.

$('#searchInput').on('keyup', function() { var searchText = $(this).val().toLowerCase(); $('#tree2 li').each(function() { var name = $(this).text().toLowerCase(); if (name.indexOf(searchText) !== -1) { $(this).addClass('intro'); tree2.openAll(); }

This is the function that I am using, but no item appears in the TreeView even if the searched item’s name matches an item in the TreeView. Also, several errors occur in the TreeView and the function enters a continuous loop of opening and closing the TreeView. Additionally, the function applies the yellow color to all items in the TreeView. Please review the errors in the function and correct them. I would be grateful for your assistance

2

Answers


  1. I checked your code (not thoroughly) and some obvious issues came to my sight at first.

    Problem:

    The tree.openAll function is generic and currently responsible for opening up all the nodes in the tree and not just the ancestors of the searched value.

    As you are calling the openAll function inside the keyup event (when the searched string matches with any of the node texts), it will trigger the generic tree.openAll function where it will not just try to open the ancestors of the searched node but all the nodes (this is happening through the click function). This is the reason you are seeing the tree opening and closing multiple times (infinite loop as you say).

    Solution:

    The approach you can take to fix the above problem:

    1. Get all the ancestors of the searched node and trigger click from
      top to bottom. You can also add the background-color one by one
      (to show it more intuitive) as they keep on opening up (Maybe, some
      fadeIn or other animation that goes with your UX design).

    2. To trigger the click from top to bottom, I suggest you create
      another function that just takes the searched node as an argument
      and inside that function, create a logic to find all the ancestors
      and trigger the click using your already created click function.

    I hope this somehow helps you. I see you have the same issue with the closeAll as well. For closing everything, this would work but for closing a few or some of the nodes, this is not the right function.

    Login or Signup to reply.
  2.         $.fn.extend({
    
          treed: function (o) {
    
            var openedClass = 'fa-minus-circle';
            var closedClass = 'fa-plus-circle';
    
            if (typeof o != 'undefined'){
              if (typeof o.openedClass != 'undefined'){
                openedClass = o.openedClass;
              }
              if (typeof o.closedClass != 'undefined'){
                closedClass = o.closedClass;
              }
            }
    
            //initialize each of the top levels
    
            var tree = $(this);
    
            tree.addClass("tree");
    
            tree.find('li').has("ul").each(function () {
    
                var branch = $(this); //li with children ul
                branch.prepend("<i class='indicator fas " + closedClass + "'></i>");
                branch.addClass('branch');
    
                // declare a flag to toggle
    
                let flag = false;
    
                branch.on('click', function (e) {
    
                    if (this == e.target) {
                        // toggle on click
    
                        flag = !flag;
                        var icon = $(this).children('i:first');
                        icon.toggleClass(openedClass + " " + closedClass); 
    
                        // show loader only when its opened, and collpase once toggled
          
                        if(flag) {
                          $(this).append("<div class='loading'><span class='fa fa-spinner fa-spin'</span></div>"); 
                          setTimeout(()=>{
                            $(this).find('.loading').remove();
                            $(this).children().children().slideToggle(400);
                          }, 400)
                        } else {
                          $(this).children().children().slideToggle(400);
                        }
                    }
    
                });
    
                branch.children().children().toggle();
    
            });
    
            //fire event from the dynamically added icon
    
            tree.find('.branch .indicator').each(function(){
    
              $(this).on('click', function () {
                  $(this).closest('li').click();
              });
    
            });
    
            //fire event to open branch if the li contains an anchor instead of text
    
            tree.find('.branch>a').each(function () {
    
                $(this).on('click', function (e) {
                    $(this).closest('li').click();
                    e.preventDefault();
                });
    
            });
    
            //fire event to open branch if the li contains a button instead of text
    
            tree.find('.branch>button').each(function () {
    
                $(this).on('click', function (e) {
                    $(this).closest('li').click();
                    e.preventDefault();
                });
    
            });
    
            //adding "openAll" and "closeAll" functions to the tree
    
            tree.openAll = function(){
              tree.find('li').has("ul").each(function () {
    
                //finding if opened or closed from icon
                //TODO: find a simpler way, like a property set on "branch"?
                var branch = $(this); //li with children ul
                var icon = branch.children('i:first');
    
                //opening all closed ones
                if(icon.hasClass(closedClass)){
                  branch.click();
                }
              });
            };
            tree.closeAll = function(){
              tree.find('li').has("ul").each(function () {
    
                //finding if opened or closed from icon
                //TODO: find a simpler way, like a property set on "branch"?
                var branch = $(this); //li with children ul
                var icon = branch.children('i:first');
    
                //opening all closed ones
                if(icon.hasClass(openedClass)){
                  branch.click();
                }
              });      
            };
    
            //return the tree so we can store it in a var and call the functions
    
            return tree;
    
          }
    
        });
    
            
    
        //Initialization of treeviews
    
        //$('#tree1').treed();
    
        var tree2 = $('#tree2').treed({openedClass:'fa-folder-open', closedClass:'fa-folder'});
    
        //code for the buttons
        $('#openall').on('click', function(){
          tree2.openAll();
        });
        $('#closeall').on('click', function(){
          tree2.closeAll();
        });
    $('#searchInput').on('keyup', function() {
      var searchText = $(this).val().toLowerCase();
      
      $('#tree2 li').each(function() {
        var name = $(this).text().toLowerCase();
        
        if (name.indexOf(searchText) !== -1) {
          $(this).show();
    
        }
    else{ 
    $(this).hide();
    }
      });
    });
            .intro {
      background-color: yellow;
    }
        .tree {
    
          overflow-y: auto;
    
        }
    
        .branch {
    
          white-space: nowrap;
    
        }
    
        .tree, .tree ul {
    
              margin:0;
    
              padding:0;
    
              list-style:none;
    
              margin-left:10px;
    
            }
    
            .tree ul {
    
              margin-left:1em;
    
              position:relative
    
            }
    
            .tree ul ul {
    
              margin-left:.5em
    
            }
    
            .tree ul:before {
    
              content:"";
    
              display:block;
    
              width:0;
    
              position:absolute;
    
              top:0;
    
              bottom:0;
    
              left:0;
    
              border-left:1px solid
    
            }
    
            .tree li {
    
              margin:0;
    
              padding:0 1em;
    
              line-height:2em;
    
              color:#369;
    
              font-weight:700;
    
              position:relative;
    
            }
    
            .tree ul li:before {
    
              content:"";
    
              display:block;
    
              width:10px;
    
              height:0;
    
              border-top:1px solid;
    
              margin-top:-1px;
    
              position:absolute;
    
              top:1em;
    
              left:0
    
            }
    
            .tree ul li:last-child:before {
    
              background:#fff;
    
              height:auto;
    
              top:1em;
    
              bottom:0
    
            }
    
            .indicator {
    
              margin-right:5px;
    
            }
    
            .tree li a {
    
              text-decoration: none;
    
              color:#369;
    
            }
    
            .tree li button, .tree li button:active, .tree li button:focus {
    
              text-decoration: none;
    
              color:#369;
    
              border:none;
    
              background:transparent;
    
              margin:0px 0px 0px 0px;
    
              padding:0px 0px 0px 0px;
    
              outline: 0;
    
            }
    
            .loading {
    
              font-style: italic;
    
            }
    
        .timeline {
    
          border-left: 1px solid hsl(0, 0%, 90%);
    
          position: relative;
    
          list-style: none;
    
        }
    
        .timeline .timeline-item {
    
          position: relative;
    
        }
    
        .timeline .timeline-item:after {
    
          position: absolute;
    
          display: block;
    
          top: 0;
    
        }
    
        .timeline .timeline-item:after {
    
          background-color: hsl(0, 0%, 90%);
    
          left: -38px;
    
          border-radius: 50%;
    
          height: 11px;
    
          width: 11px;
    
          content: "";
    
        }
            <section class="content">
    
          <div class="container-fluid">
    
          <div class="card">
    
            <div class="card-body">              
    
              <div class="row">
    
                <div class="col-md-4">
    <div class="input-group mb-3">
      <span class="input-group-text" id="basic-addon1"> <i class="fa fa-search"></i></span>
      <input type="text" class="form-control" id="searchInput"  aria-label="Username" aria-describedby="basic-addon1">
    </div>
    <br>
                
    
        <button type="button" id ="openall"class="btn btn-warning" id ">open All</button>
        <button type="button" id="closeall" class="btn btn-info">closeAll</button>
    <br>
    <ul id="tree2">
                  <li>
    
                  <a href="#">TECH</a>
    
                  <ul>
    
                    <li>Company Maintenance</li>
    
                    <li>
    
                      Employees
    
                      <ul>
    
                        <li>
    
                        Reports
    
                        <ul>
    
                          <li>Report1
    
                          <ul>
    
                          <li>Report1
    
                          <ul>
    
                          <li>Report1
    
                          <ul>
    
                          <li>Report1</li>
    
                          <li>Report2</li>
    
                          <li>Report3</li>
    
                        </ul>
    
                          </li>
    
                          <li>Report2</li>
    
                          <li>Report3</li>
    
                        </ul>
    
                          </li>
    
                          <li>Report2</li>
    
                          <li>Report3</li>
    
                        </ul>
    
                          </li>
    
                          <li>Report2</li>
    
                          <li>Report3</li>
    
                        </ul>
    
                        </li>
    
                        <li>Employee Maint.</li>
    
                      </ul>
    
                    </li>
    
                    <li>Human Resources</li>
    
                  </ul>
    
                  </li>
    
                     </ul>
    
              </div>        
    
              </div>
    
           </div>
    
          <div class="card-footer text-body-secondary">
    
        </div> 
    
        </div>  <!-- /.container-fluid -->
    
           </section>
    
                            
    
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.rtl.min.css">
    
           <link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet">
    
        <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.0/css/all.css" integrity="sha384-lZN37f5QGtY3VHgisS14W3ExzMWZxybE1SJSEsQp9S+oqd12jhcu+A56Ebc1zFSJ" crossorigin="anonymous">
    
        <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    
    
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm" crossorigin="anonymous"></script>
    
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.js"></script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search