2016-01-04 58 views
15

我使用的是https://github.com/tchatel/angular-treeRepeat,並試圖過濾未擴展的節點。所以我修改這個代碼,包括AngularJS過濾:AngularJS過濾器不擴展已過濾的節點

treeRepeat.html:

<p id="expand-collapse-all"> 
    <a href="" ng-click="expandAll()">Expand all</a> 
    <a href="" ng-click="collapseAll()">Collapse all</a> 
</p> 


Filter : <input ng-model="myFilter" type="text"> 

<ul frang-tree> 
    <li frang-tree-repeat="node in treeData | filter:myFilter"> 
     <div><span class="icon" 
       ng-class="{collapsed: node.collapsed, expanded: !node.collapsed}" 
       ng-show="node.children && node.children.length > 0" 
       ng-click="node.collapsed = !node.collapsed"></span> 
      <span class="label" 
       ng-class="{folder: node.children && node.children.length > 0}" 
       ng-bind="node.label" 
       ng-click="action(node)"></span> 
     </div> 
     <ul ng-if="!node.collapsed && node.children && node.children.length > 0" 
      frang-tree-insert-children="node.children | filter:myFilter"></ul> 
    </li> 
</ul> 

可正常工作,如果所有的樹節點展開: 線20 controllers.js:

$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 } ] } ] } ]"); 

但是,如果節點已摺疊,則匹配的節點將展開/可見。樹仍然崩潰。配置了摺疊節點: 上controllers.js線21:

$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 } ] } ] } ]"); 

Plunkr:https://plnkr.co/edit/CtXlRfdreolTTc018c0A?p=preview

我需要手動展開節點的用戶類型或者是有角度的配置,我可以用它來擴大這些節點?

我試着補充說,每次觸發用戶類型的自定義函數:

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

    }); 
    } 
} 

但是,這是非常低效的,因爲它遍歷整個樹結構爲每個關鍵字的用戶類型。這也適用於完全匹配的文本:searchText.toLowerCase() === childNode.label.toLowerCase()。嘗試使用contains而不是===沒有成功。

plnkr源:

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 : 


<!doctype html> 
<html lang="en" ng-app="app"> 
<head> 
    <meta charset="utf-8"> 
    <title>treeRepeat demo</title> 
    <link rel="stylesheet" href="app.css"/> 
</head> 

<body> 

    <h1>treeRepeat</h1> 
    <div id="menu" ng-controller="MenuCtrl"> 
     <ul> 
      <li ng-repeat="item in menu" ng-class="{selected: item == getCurrentMenuItem()}"><a href="#/{{item.index}}">{{item.shortLabel}}</a></li> 
     </ul> 
     <h2>{{getCurrentMenuItem().fullLabel}}</h2> 
    </div> 

    <ng-view></ng-view> 

    <script src="angular.js"></script> 
    <script src="angular-route.js"></script> 
    <script src="app.js"></script> 
    <script src="services.js"></script> 
    <script src="controllers.js"></script> 
    <script src="filters.js"></script> 
    <script src="directives.js"></script> 
</body> 
</html> 

services.js : 

'use strict'; 

angular.module('app.services', []) 
    .constant('menu', []); 

treerepeat.html : 

<p id="expand-collapse-all"> 
    <a href="" ng-click="expandAll()">Expand all</a> 
    <a href="" ng-click="collapseAll()">Collapse all</a> 
</p> 


Filter : <input ng-model="myFilter" type="text"> 

<ul frang-tree> 
    <li frang-tree-repeat="node in treeData | filter:myFilter"> 
     <div><span class="icon" 
       ng-class="{collapsed: node.collapsed, expanded: !node.collapsed}" 
       ng-show="node.children && node.children.length > 0" 
       ng-click="node.collapsed = !node.collapsed"></span> 
      <span class="label" 
       ng-class="{folder: node.children && node.children.length > 0}" 
       ng-bind="node.label" 
       ng-click="action(node)"></span> 
     </div> 
     <ul ng-if="!node.collapsed && node.children && node.children.length > 0" 
      frang-tree-insert-children="node.children | filter:myFilter"></ul> 
    </li> 
</ul> 
+0

並非所有的場景展開的節點工程。全部展開並搜索「A」。應該像搜索'文件A'一樣工作。對? – Valijon

+0

@Valijon是的,似乎工作,只有問題是,當用戶從文本框中刪除所有文本樹仍然展開,我應該能夠檢查這種情況下,只是重新加載樹:https://plnkr.co/edit/CtXlRfdreolTTc018c0A ?p =預覽 –

+0

@ blue-sky您是否只想對尚未展開的節點進行過濾? –

回答

4

您可以通過使用過濾器具有predicate功能實現這一目標。

function(value,index):可以使用謂詞函數來寫入任意過濾器。該函數針對數組的每個元素進行調用。最終結果是謂詞返回true的那些元素的數組。

  1. 創建一個斷言函數

$scope.getFilter = function(value, index){ 
    if(!$scope.myFilter || $scope.myFilter === '' && (value.label === 'root')){ 
     $scope.collapseAll(); 
     return true; 
    } 
    if (findMatch(value, $scope.myFilter)){ 
     value.collapsed = false; 
     return true; 
    }else{ 
     value.collapsed = true; 
     return false; 
    } 
} 
  • 創建,檢查一個函數如果當前項是一個匹配(這個函數被調用來自謂詞函數)

  • function findMatch(value, filter) { 
        var found = false; 
        if(value.label.toLowerCase().indexOf(filter) > -1){ 
         value.collapsed = false; 
         found = true; 
        } 
        if(!value.children || value.children.length===0){ 
         if(value.collapsed!== undefined){ 
          value.collapsed = true; 
          return found; 
          } 
         } 
         for (var i = 0; i < value.children.length; i++) { 
          if (value.children[i].label.toLowerCase().indexOf(filter) > -1) { 
           //match found 
           value.collapsed = false; 
           value.children[i].collapsed = false; 
           found = true; 
          } else { 
           //check child items 
           if(value.children[i].children && value.children[i].children.length>0) 
           { 
            if (findMatchingChildren(value.children[i].children, filter)) { 
            value.children[i].collapsed = false; 
            found = true; 
            }else{ 
            value.children[i].collapsed = true; 
            } 
           } 
          } 
         } 
    
         return found; 
    } 
    

    3.創建一個循環通過當前項目的子項目的函數,此函數在步驟2中調用該函數。最終得到一個遞歸函數,用於檢查所有級別。

    function findMatchingChildren(children, filter) { 
        var found = false; 
        for (var i = 0; i < children.length; i++) { 
         if (findMatch(children[i], filter)) { 
          children[i].collapsed = false; 
          found = true; 
         }else{ 
          children[i].collapsed = true; 
         } 
        } 
        return found; 
    } 
    

    當你找到匹配的項目,你設定的collapsed價值false

    請參閱工作示例here

    HTML

    <p id="expand-collapse-all"> 
        <a href="" ng-click="expandAll()">Expand all</a> 
        <a href="" ng-click="collapseAll()">Collapse all</a> 
    </p> 
    Filter : <input ng-model="myFilter" type="text"> 
    <ul frang-tree> 
        <li frang-tree-repeat="node in treeData | filter:getFilter"> 
         <div> 
          <span class="icon" 
           ng-class="{collapsed: node.collapsed, expanded: !node.collapsed}" 
           ng-show="node.children && node.children.length > 0" 
           ng-click="node.collapsed = !node.collapsed"></span> 
          <span class="label" 
           ng-class="{folder: node.children && node.children.length > 0}" 
           ng-bind="node.label" 
           ng-click="action(node)"></span> 
         </div> 
         <ul ng-if="!node.collapsed && node.children && node.children.length>0" frang-tree-insert-children="node.children | filter:myFilter"></ul> 
    </li> 
    </ul> 
    
    +0

    謝謝,但是「plnkr.co/edit/CtXlRfdreolTTc018c0A?p=preview-藍天1月7日13:22」不是一個更簡單的解決方案嗎? –

    0

    考慮完全拋棄了angular-treeRepeat模塊,並使用遞歸模板。 Ben Foster解釋了它在blog post中的工作原理,我認爲這是一種更加優雅(也不太複雜)的解決方案。

    帶過濾器的工作例如:JSFiddle

    HTML:

    <div ng-app="app" ng-controller='AppCtrl'> 
        Filter: <input ng-model="myFilter" type="text"> 
        <script type="text/ng-template" id="categoryTree"> 
        {{ category.title }} 
        <ul ng-show="category.categories"> 
         <li 
         ng-repeat="category in category.categories | filter:myFilter" 
         ng-include="'categoryTree'"> 
         </li> 
        </ul> 
        </script> 
        <ul> 
        <li 
         ng-repeat="category in categories | filter:myFilter" 
         ng-include="'categoryTree'"> 
        </li> 
        </ul> 
    </div> 
    

    的JavaScript:

    var app = angular.module('app', []) 
        .controller('AppCtrl', function($scope) { 
        $scope.categories = [{ 
         title: 'Computers', 
         categories: [{ 
          title: 'Laptops', 
          categories: [{ 
          title: 'Ultrabooks' 
          },{ 
          title: 'Macbooks' 
          }] 
         },{ 
          title: 'Desktops' 
         },{ 
          title: 'Tablets', 
          categories: [{ 
          title: 'Apple' 
          },{ 
          title: 'Android' 
          }] 
         } 
         ] 
        },{ 
         title: 'Printers' 
        }]; 
        });