title: AngularJS filter not expanding filtered nodes
body: <p>I'm using <a href="https://github.com/tchatel/angular-treeRepeat">https://github.com/tchatel/angular-treeRepeat</a> and am attempting to filter nodes that have not expanded. So I've modified this code to include AngularJS filter : </p>
  
  <p>treeRepeat.html : </p>
  
  <pre><code>&lt;p id="expand-collapse-all"&gt;
      &lt;a href="" ng-click="expandAll()"&gt;Expand all&lt;/a&gt;
      &lt;a href="" ng-click="collapseAll()"&gt;Collapse all&lt;/a&gt;
  &lt;/p&gt;
  
  
  Filter : &lt;input ng-model="myFilter" type="text"&gt;
  
  &lt;ul frang-tree&gt;
    &lt;li frang-tree-repeat="node in treeData | filter:myFilter"&gt;
        &lt;div&gt;&lt;span class="icon"
                   ng-class="{collapsed: node.collapsed, expanded: !node.collapsed}"
                   ng-show="node.children &amp;&amp; node.children.length &gt; 0"
                   ng-click="node.collapsed = !node.collapsed"&gt;&lt;/span&gt;
             &lt;span class="label"
                   ng-class="{folder: node.children &amp;&amp; node.children.length &gt; 0}"
                   ng-bind="node.label"
                   ng-click="action(node)"&gt;&lt;/span&gt;
        &lt;/div&gt;
        &lt;ul ng-if="!node.collapsed &amp;&amp; node.children &amp;&amp; node.children.length &gt; 0"
            frang-tree-insert-children="node.children  | filter:myFilter"&gt;&lt;/ul&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  </code></pre>
  
  <p>This works as expected if all of the tree nodes are expanded : 
  Line 20 on controllers.js : </p>
  
  <pre><code>$scope.treeData = JSON.parse("[ { \"label\": \"root\", \"children\": [ { \"label\": \"folder A\", \"collapsed\": true, \"children\": [ { \"label\": \"folder B\", \"collapsed\": true, \"children\": [ { \"label\": \"file B1\", \"collapsed\": true }, { \"label\": \"file B2\", \"collapsed\": true } ] }, { \"label\": \"file A1\", \"collapsed\": true }, { \"label\": \"file A2\", \"collapsed\": true }, { \"label\": \"file A3\", \"collapsed\": true }, { \"label\": \"file A4\", \"collapsed\": true } ] }, { \"label\": \"folder C\", \"collapsed\": true, \"children\": [ { \"label\": \"folder D\", \"collapsed\": true, \"children\": [ { \"label\": \"folder E\", \"collapsed\": true, \"children\": [ { \"label\": \"file E1\", \"collapsed\": true }, { \"label\": \"file E2\", \"collapsed\": true }, { \"label\": \"file E3\", \"collapsed\": true } ] } ] }, { \"label\": \"folder F\", \"collapsed\": true, \"children\": [ { \"label\": \"file F1\", \"collapsed\": true }, { \"label\": \"file F2\", \"collapsed\": true } ] }, { \"label\": \"file C1\", \"collapsed\": true } ] }, { \"label\": \"folder G\", \"collapsed\": true, \"children\": [ { \"label\": \"file G1\", \"collapsed\": true }, { \"label\": \"file G2\", \"collapsed\": true }, { \"label\": \"file G3\", \"collapsed\": true }, { \"label\": \"file G4\", \"collapsed\": true } ] }, { \"label\": \"folder H\", \"collapsed\": true, \"children\": [ { \"label\": \"file H1\", \"collapsed\": true }, { \"label\": \"file H2\", \"collapsed\": true }, { \"label\": \"file H3\", \"collapsed\": true } ] } ] } ]");
  </code></pre>
  
  <p>But if the nodes are collapsed then the matched nodes expanded / viewable. The tree remains collapsed. Config for collapsed nodes : 
  Line 21 on controllers.js : </p>
  
  <pre><code>$scope.treeData = JSON.parse("[ { \"label\": \"root\", \"children\": [ { \"label\": \"folder A\", \"collapsed\": true, \"children\": [ { \"label\": \"folder B\", \"collapsed\": true, \"children\": [ { \"label\": \"file B1\", \"collapsed\": true }, { \"label\": \"file B2\", \"collapsed\": true } ] }, { \"label\": \"file A1\", \"collapsed\": true }, { \"label\": \"file A2\", \"collapsed\": true }, { \"label\": \"file A3\", \"collapsed\": true }, { \"label\": \"file A4\", \"collapsed\": true } ] }, { \"label\": \"folder C\", \"collapsed\": true, \"children\": [ { \"label\": \"folder D\", \"collapsed\": true, \"children\": [ { \"label\": \"folder E\", \"collapsed\": true, \"children\": [ { \"label\": \"file E1\", \"collapsed\": true }, { \"label\": \"file E2\", \"collapsed\": true }, { \"label\": \"file E3\", \"collapsed\": true } ] } ] }, { \"label\": \"folder F\", \"collapsed\": true, \"children\": [ { \"label\": \"file F1\", \"collapsed\": true }, { \"label\": \"file F2\", \"collapsed\": true } ] }, { \"label\": \"file C1\", \"collapsed\": true } ] }, { \"label\": \"folder G\", \"collapsed\": true, \"children\": [ { \"label\": \"file G1\", \"collapsed\": true }, { \"label\": \"file G2\", \"collapsed\": true }, { \"label\": \"file G3\", \"collapsed\": true }, { \"label\": \"file G4\", \"collapsed\": true } ] }, { \"label\": \"folder H\", \"collapsed\": true, \"children\": [ { \"label\": \"file H1\", \"collapsed\": true }, { \"label\": \"file H2\", \"collapsed\": true }, { \"label\": \"file H3\", \"collapsed\": true } ] } ] } ]");
  </code></pre>
  
  <p>Plunkr : <a href="https://plnkr.co/edit/CtXlRfdreolTTc018c0A?p=preview">https://plnkr.co/edit/CtXlRfdreolTTc018c0A?p=preview</a></p>
  
  <p>Do I need to manually expand the nodes as the user types or is there an angular config I can use to expand these nodes ?</p>
  
  <p>I've tried adding a custom function that fires everytime user types : </p>
  
  <pre><code>  function matchChildNode(objData , parentNode) {
  
          angular.forEach(objData, function(childNode, key) {
  
                  var searchText = "";
                  //AngularJS does not initialise the searchText var until used. As the function is re-initialised for every node
                  //need to check if is undefined
                  if ($scope.searchText == undefined) {
                      searchText = ""
                  } else {
                      searchText = $scope.searchText
                  }
  
                  if (searchText.toLowerCase() === childNode.label.toLowerCase()) {
                      parentNode.collapsed = false
                  }       
  
                  matchChildNode(childNode.children , childNode);
  
    });
    } 
  }
  </code></pre>
  
  <p>But this is very inefficient as it traverses entire tree structure for each keyword user types. This also just works for exactly matched text : <code>searchText.toLowerCase() === childNode.label.toLowerCase()</code> . Have tried using <code>contains</code> instead of <code>===</code> with no success.</p>
  
  <p>plnkr src : </p>
  
  <pre><code>app.css (removed due to stackoverflow 30000 character limitation when asking questions) 
  
  directives.js (removed due to stackoverflow 30000 character limitation when asking questions) 
  
  filter.js : 
  
  'use strict';
  
  angular.module('app.filters', []);
  
  index.html : 
  
  
  &lt;!doctype html&gt;
  &lt;html lang="en" ng-app="app"&gt;
  &lt;head&gt;
    &lt;meta charset="utf-8"&gt;
    &lt;title&gt;treeRepeat demo&lt;/title&gt;
    &lt;link rel="stylesheet" href="app.css"/&gt;
  &lt;/head&gt;
  
  &lt;body&gt;
  
    &lt;h1&gt;treeRepeat&lt;/h1&gt;
    &lt;div id="menu" ng-controller="MenuCtrl"&gt;
        &lt;ul&gt;
            &lt;li ng-repeat="item in menu" ng-class="{selected: item == getCurrentMenuItem()}"&gt;&lt;a href="#/{{item.index}}"&gt;{{item.shortLabel}}&lt;/a&gt;&lt;/li&gt;
        &lt;/ul&gt;
        &lt;h2&gt;{{getCurrentMenuItem().fullLabel}}&lt;/h2&gt;
    &lt;/div&gt;
  
    &lt;ng-view&gt;&lt;/ng-view&gt;
  
    &lt;script src="angular.js"&gt;&lt;/script&gt;
    &lt;script src="angular-route.js"&gt;&lt;/script&gt;
    &lt;script src="app.js"&gt;&lt;/script&gt;
    &lt;script src="services.js"&gt;&lt;/script&gt;
    &lt;script src="controllers.js"&gt;&lt;/script&gt;
    &lt;script src="filters.js"&gt;&lt;/script&gt;
    &lt;script src="directives.js"&gt;&lt;/script&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  
  services.js : 
  
  'use strict';
  
  angular.module('app.services', [])
      .constant('menu', []);
  
  treerepeat.html : 
  
  &lt;p id="expand-collapse-all"&gt;
      &lt;a href="" ng-click="expandAll()"&gt;Expand all&lt;/a&gt;
      &lt;a href="" ng-click="collapseAll()"&gt;Collapse all&lt;/a&gt;
  &lt;/p&gt;
  
  
  Filter : &lt;input ng-model="myFilter" type="text"&gt;
  
  &lt;ul frang-tree&gt;
    &lt;li frang-tree-repeat="node in treeData | filter:myFilter"&gt;
        &lt;div&gt;&lt;span class="icon"
                   ng-class="{collapsed: node.collapsed, expanded: !node.collapsed}"
                   ng-show="node.children &amp;&amp; node.children.length &gt; 0"
                   ng-click="node.collapsed = !node.collapsed"&gt;&lt;/span&gt;
             &lt;span class="label"
                   ng-class="{folder: node.children &amp;&amp; node.children.length &gt; 0}"
                   ng-bind="node.label"
                   ng-click="action(node)"&gt;&lt;/span&gt;
        &lt;/div&gt;
        &lt;ul ng-if="!node.collapsed &amp;&amp; node.children &amp;&amp; node.children.length &gt; 0"
            frang-tree-insert-children="node.children  | filter:myFilter"&gt;&lt;/ul&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  </code></pre>