2017-07-28 62 views
3

我已經構建了以下顯示層次結構的Angular應用程序:將篩選應用於分層結構

我試圖在此層次結構頂部插入文本框。過濾底部的數據。已經嘗試過幾個過濾器的例子,但迄今爲止還沒有多少運氣。

我想要做的就是利用角度綁定,當用戶開始鍵入文本框,動態擴展和摺疊層次結構並突出顯示匹配。

尋找一些建議什麼是解決這個問題的最佳方法。請注意,層次結構可能變大並且有大約3000條記錄。

angular.module('HelloWorldApp', []) 
 
    .controller('HelloWorldController', function($scope) { 
 

 
    $scope.mp6Root = []; 
 
    $scope.mp6Data = []; 
 

 
    var data = [ 
 
    { 
 
     "cls": "L2-013551", 
 
     "clsNm": "FASHION DOLLS", 
 
     "subCt": "L3-001793", 
 
     "subCtNm": "FASHION DOLLS AND ACCESSORIES", 
 
     "ct": "L4-000429", 
 
     "ctNm": "DOLLS GAMES PUZZLES", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-006472", 
 
     "clsNm": "FASHION DOLL WITH ACCS", 
 
     "subCt": "L3-001793", 
 
     "subCtNm": "FASHION DOLLS AND ACCESSORIES", 
 
     "ct": "L4-000429", 
 
     "ctNm": "DOLLS GAMES PUZZLES", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-014668", 
 
     "clsNm": "ACTIVITIES", 
 
     "subCt": "L3-001793", 
 
     "subCtNm": "FASHION DOLLS AND ACCESSORIES", 
 
     "ct": "L4-000429", 
 
     "ctNm": "DOLLS GAMES PUZZLES", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-014667", 
 
     "clsNm": "STORAGE", 
 
     "subCt": "L3-001793", 
 
     "subCtNm": "FASHION DOLLS AND ACCESSORIES", 
 
     "ct": "L4-000429", 
 
     "ctNm": "DOLLS GAMES PUZZLES", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-014675", 
 
     "clsNm": "FASHION DOLL PLAYSET", 
 
     "subCt": "L3-001793", 
 
     "subCtNm": "FASHION DOLLS AND ACCESSORIES", 
 
     "ct": "L4-000429", 
 
     "ctNm": "DOLLS GAMES PUZZLES", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-006476", 
 
     "clsNm": "ROLE PLAY FASHION AND TOY", 
 
     "subCt": "L3-001793", 
 
     "subCtNm": "FASHION DOLLS AND ACCESSORIES", 
 
     "ct": "L4-000429", 
 
     "ctNm": "DOLLS GAMES PUZZLES", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-014677", 
 
     "clsNm": "CORE PS FIGURE W PLAYSET", 
 
     "subCt": "L3-001798", 
 
     "subCtNm": "CORE PRESCHOOL TOYS", 
 
     "ct": "L4-000428", 
 
     "ctNm": "PRESCHOOL", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-006508", 
 
     "clsNm": "CORE PS MUSICAL INSTRUMENT", 
 
     "subCt": "L3-001798", 
 
     "subCtNm": "CORE PRESCHOOL TOYS", 
 
     "ct": "L4-000428", 
 
     "ctNm": "PRESCHOOL", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-014788", 
 
     "clsNm": "WAGONS TOYS", 
 
     "subCt": "L3-001798", 
 
     "subCtNm": "CORE PRESCHOOL TOYS", 
 
     "ct": "L4-000428", 
 
     "ctNm": "PRESCHOOL", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-006536", 
 
     "clsNm": "RIDING TOYS FOOT TO FLOOR", 
 
     "subCt": "L3-001798", 
 
     "subCtNm": "CORE PRESCHOOL TOYS", 
 
     "ct": "L4-000428", 
 
     "ctNm": "PRESCHOOL", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-014678", 
 
     "clsNm": "CORE PS PUZZLE", 
 
     "subCt": "L3-001798", 
 
     "subCtNm": "CORE PRESCHOOL TOYS", 
 
     "ct": "L4-000428", 
 
     "ctNm": "PRESCHOOL", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-006506", 
 
     "clsNm": "CORE PS FIGURE PLAYSET", 
 
     "subCt": "L3-001798", 
 
     "subCtNm": "CORE PRESCHOOL TOYS", 
 
     "ct": "L4-000428", 
 
     "ctNm": "PRESCHOOL", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-006509", 
 
     "clsNm": "CORE PS OTHER TOYS", 
 
     "subCt": "L3-001798", 
 
     "subCtNm": "CORE PRESCHOOL TOYS", 
 
     "ct": "L4-000428", 
 
     "ctNm": "PRESCHOOL", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-006511", 
 
     "clsNm": "CORE PS TALKING SOUND", 
 
     "subCt": "L3-001798", 
 
     "subCtNm": "CORE PRESCHOOL TOYS", 
 
     "ct": "L4-000428", 
 
     "ctNm": "PRESCHOOL", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-006507", 
 
     "clsNm": "CORE PS LEARNING TOY", 
 
     "subCt": "L3-001798", 
 
     "subCtNm": "CORE PRESCHOOL TOYS", 
 
     "ct": "L4-000428", 
 
     "ctNm": "PRESCHOOL", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-006510", 
 
     "clsNm": "CORE PS ROLEPLAY", 
 
     "subCt": "L3-001798", 
 
     "subCtNm": "CORE PRESCHOOL TOYS", 
 
     "ct": "L4-000428", 
 
     "ctNm": "PRESCHOOL", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-006512", 
 
     "clsNm": "CORE PS VEHICLES", 
 
     "subCt": "L3-001798", 
 
     "subCtNm": "CORE PRESCHOOL TOYS", 
 
     "ct": "L4-000428", 
 
     "ctNm": "PRESCHOOL", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-006585", 
 
     "clsNm": "DIECAST MED LG SCALE VEHICLES", 
 
     "subCt": "L3-001818", 
 
     "subCtNm": "DIECAST AND PLAYSETS", 
 
     "ct": "L4-000425", 
 
     "ctNm": "ACT FIGS CONSTRUCTION VEHICLES", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-006587", 
 
     "clsNm": "DIECAST PLAYSETS", 
 
     "subCt": "L3-001818", 
 
     "subCtNm": "DIECAST AND PLAYSETS", 
 
     "ct": "L4-000425", 
 
     "ctNm": "ACT FIGS CONSTRUCTION VEHICLES", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-006586", 
 
     "clsNm": "DIECAST MINI VEHICLES", 
 
     "subCt": "L3-001818", 
 
     "subCtNm": "DIECAST AND PLAYSETS", 
 
     "ct": "L4-000425", 
 
     "ctNm": "ACT FIGS CONSTRUCTION VEHICLES", 
 
     "seg": "L5-000031", 
 
     "segNm": "TOYS", 
 
     "area": "L6-000004", 
 
     "areaNm": "HARDLINES" 
 
    }, 
 
    { 
 
     "cls": "L2-006798", 
 
     "clsNm": "VACUUMS UPRIGHT BAGLESS", 
 
     "subCt": "L3-001851", 
 
     "subCtNm": "FLOOR CLEANING", 
 
     "ct": "L4-000449", 
 
     "ctNm": "HOME ELECTRICS", 
 
     "seg": "L5-000054", 
 
     "segNm": "HARD HOME", 
 
     "area": "L6-000012", 
 
     "areaNm": "IN AND OUTDOOR HOME" 
 
    }, 
 
    { 
 
     "cls": "L2-006795", 
 
     "clsNm": "VACUUMS HAND", 
 
     "subCt": "L3-001851", 
 
     "subCtNm": "FLOOR CLEANING", 
 
     "ct": "L4-000449", 
 
     "ctNm": "HOME ELECTRICS", 
 
     "seg": "L5-000054", 
 
     "segNm": "HARD HOME", 
 
     "area": "L6-000012", 
 
     "areaNm": "IN AND OUTDOOR HOME" 
 
    }, 
 
    { 
 
     "cls": "L2-006791", 
 
     "clsNm": "FLOOR DEEP CLEANER CHEMICALS", 
 
     "subCt": "L3-001851", 
 
     "subCtNm": "FLOOR CLEANING", 
 
     "ct": "L4-000449", 
 
     "ctNm": "HOME ELECTRICS", 
 
     "seg": "L5-000054", 
 
     "segNm": "HARD HOME", 
 
     "area": "L6-000012", 
 
     "areaNm": "IN AND OUTDOOR HOME" 
 
    }, 
 
    { 
 
     "cls": "L2-006796", 
 
     "clsNm": "VACUUMS STICK", 
 
     "subCt": "L3-001851", 
 
     "subCtNm": "FLOOR CLEANING", 
 
     "ct": "L4-000449", 
 
     "ctNm": "HOME ELECTRICS", 
 
     "seg": "L5-000054", 
 
     "segNm": "HARD HOME", 
 
     "area": "L6-000012", 
 
     "areaNm": "IN AND OUTDOOR HOME" 
 
    }, 
 
    { 
 
     "cls": "L2-012895", 
 
     "clsNm": "FLOOR STEAM MOPS", 
 
     "subCt": "L3-001851", 
 
     "subCtNm": "FLOOR CLEANING", 
 
     "ct": "L4-000449", 
 
     "ctNm": "HOME ELECTRICS", 
 
     "seg": "L5-000054", 
 
     "segNm": "HARD HOME", 
 
     "area": "L6-000012", 
 
     "areaNm": "IN AND OUTDOOR HOME" 
 
    }] 
 
    ; 
 
     
 
    $scope.loadMP6DataToMemory = function(data) { 
 

 
     angular.forEach(data, function (value, key) { 
 

 
      if ($.inArray(value.area, $scope.mp6Root) === -1) { 
 
       $scope.mp6Root.push(value.area); 
 
      } 
 
      
 
      addToMap(value.cls, value.clsNm, ""); 
 
      addToMap(value.subCt, value.subCtNm, value.cls); 
 
      addToMap(value.ct, value.ctNm, value.subCt); 
 
      addToMap(value.seg, value.segNm, value.ct); 
 
      addToMap(value.area, value.areaNm, value.seg); 
 
     }); 
 
    } 
 

 
    addToMap = function (pKey, pName, pChild) { 
 
     if (!$scope.mp6Data[pKey]) { 
 
      cSet = []; 
 
      $scope.mp6Data[pKey] = { name: pName, children: cSet }; 
 
     } else { 
 
      if ($.inArray(pChild, $scope.mp6Data[pKey].children) === -1) { 
 
       $scope.mp6Data[pKey].children.push(pChild); 
 
      } 
 
     } 
 
    } 
 

 
    $scope.ExpandMP6 = function (pKey) { 
 
     if (pKey) { 
 
      mp = $scope.mp6Data[pKey]; 
 
      return { 
 
       name: mp.name, 
 
       children: mp.children, 
 
       visible: false 
 
      } 
 
     } 
 
    } 
 

 

 
    $scope.loadMP6DataToMemory(data); 
 

 
    $scope.l5visible = false; 
 
    $scope.l4visible = false; 
 
    $scope.l3visible = false; 
 
    $scope.l2visible = false; 
 

 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 
<div class="container" ng-app="HelloWorldApp" ng-controller="HelloWorldController"> 
 

 
      <div class="md-grid"> 
 
       <ul class="md-list"> 
 
        <li class="md-list-item-text" ng:repeat="l6 in mp6Root" ng-click="l5visible = !l5visible; $event.stopPropagation();"> 
 
         L6 {{ExpandMP6(l6).name}} 
 
         <ul class="md-list" ng-show="l5visible"> 
 
          <li class="md-list-item-text" ng:repeat="l5 in ExpandMP6(l6).children" ng-click="l4visible = !l4visible; $event.stopPropagation();"> 
 
           L5 {{ExpandMP6(l5).name}} 
 
           <ul class="md-list" ng-show="l4visible"> 
 
            <li class="md-list-item-text" ng:repeat="l4 in ExpandMP6(l5).children" ng-click="l3visible = !l3visible; $event.stopPropagation();"> 
 
             L4 {{ExpandMP6(l4).name}} 
 
             <ul class="md-list" ng-show="l3visible"> 
 
              <li class="md-list-item-text" ng:repeat="l3 in ExpandMP6(l4).children" ng-click="l2visible = !l2visible; $event.stopPropagation();"> 
 
               L3 {{ExpandMP6(l3).name}} 
 
               <ul class="md-list" ng-show="l2visible"> 
 
                <li class="md-list-item-text" ng:repeat="l2 in ExpandMP6(l3).children"> 
 
                 L2 {{ExpandMP6(l2).name}} 
 
                </li> 
 
               </ul> 
 
              </li> 
 
             </ul> 
 
            </li> 
 
           </ul> 
 
          </li> 
 
         </ul> 
 
        </li> 
 
       </ul> 
 
      </div> 
 
      </div>

編輯: 這是我的想法,但似乎並沒有在路上IVE適應過濾器結構的HTML: how to filter the data from text box in angularjs

如果HTML結構需要改變我打開的建議。

+1

聽起來像是一個非常有趣的任務。我會編寫一個函數,用[Array.prototype.filter](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)過濾列表,然後遍歷父母向他們展示一切。儘管我對Angular一無所知。 – Danmoreng

+0

它是一個有趣的方法,缺點是我需要存儲父路徑,並以某種方式能夠重建列表向後。 – otc

+0

你想過濾出它嵌套的孩子嗎?或單獨的頂級? –

回答

3

首先,你應該創建一個嵌套指令來顯示你的樹。如果突然顯示7個級別會怎麼樣?所以首先我會寫一個遞歸指令,這也會減少代碼的大小。

對於數據篩選部分,您可以使用input,並將ng-model-options="{debounce: 300}"ng-change="filterFunction()"結合使用,以便在用戶完成搜索後僅應用300毫秒。 filterFunction()一旦您的數據以層次結構形式構建,並且可以更改對象狀態以嚮應用程序顯示的指示信息指示,並且顯示其子項,則易於編寫filterFunction()

結果看起來是這樣的:

MainController.js

var app = angular.module('app', []); 
app.controller('MainController', [function() { 
    var ctrl = this; 
    ctrl.search = ''; 
    initHierarchies(); // function that transforms the data in hierarchical form 
    // filterHierarchies is called everytime the user changed the search input 
    ctrl.filterHierarchies = function() { 
    ctrl.filteredHierarchies = hierarchiesFilter(ctrl.hierarchies, ctrl.search).hierarchies; 
    } 
    ctrl.filterHierarchies(); // init the filteredHierarchies data. 

    // function that filters the hierarchy. It is a recursive function 
    function hierarchiesFilter(hierarchies, search) { 
    if (!hierarchies || !hierarchies.length) { 
     return { hierarchies: [], hasExpandedChildren: false}; 
    } 
    console.log(hierarchies, search); 
    var oneIsExpanded = false; 
    for (var i = 0; i < hierarchies.length; i++) { 
     hierarchies[i].showChildren = false; 
     if (search.length) { 
     var rx = new RegExp(search, 'i'); 
     if (hierarchies[i].name.match(rx)) { 
      oneIsExpanded = true; 
     } 
     } 
     // if the node has children which are expanded, we need to display it so its children that 
     // should be highlighted are visible 
     var hasExpandedChildren = hierarchiesFilter(hierarchies[i].children, search).hasExpandedChildren; 
     if (hasExpandedChildren) { 
     hierarchies[i].showChildren = true; 
     oneIsExpanded = true; 
     } 
    } 
    return { hierarchies: hierarchies, hasExpandedChildren: oneIsExpanded }; 
    }; 

    // function to transform the array data to a hierarchical structure 
    function initHierarchies() { 
    var data = getData(); 
    var mp6Data = {}; 
    var mp6Root = []; 

    angular.forEach(data, function (value, key) { 
     if (mp6Root.indexOf(value.area) === -1) { 
      mp6Root.push(value.area); 
     } 

     addToMap(value.cls, value.clsNm, ""); 
     addToMap(value.subCt, value.subCtNm, value.cls); 
     addToMap(value.ct, value.ctNm, value.subCt); 
     addToMap(value.seg, value.segNm, value.ct); 
     addToMap(value.area, value.areaNm, value.seg); 
    }); 

    function addToMap(pKey, pName, pChild) { 
     if (!mp6Data[pKey]) { 
      mp6Data[pKey] = { name: pName, childrenKeys: [] }; 
     } else { 
      if (mp6Data[pKey].childrenKeys.indexOf(pChild) === -1) { 
       mp6Data[pKey].childrenKeys.push(pChild); 
      } 
     } 
    } 

    function buildHierarchicalStructure(childrenKeys) { 
     var builtChildren = []; 
     for (var i = 0; i < childrenKeys.length; i++) { 
     builtChildren.push({ 
      name: mp6Data[childrenKeys[i]].name, 
      children: buildHierarchicalStructure(mp6Data[childrenKeys[i]].childrenKeys) 
     }); 
     } 
     return builtChildren; 
    } 

    for (var i = 0; i < mp6Data.length; i++) { 
     mp6Data[i].showChildren = true; 
    } 
    ctrl.hierarchies = buildHierarchicalStructure(mp6Root); 
    } 
}]); 

hierarchy.directive.js

app.directive('hierarchy', ['RecursionHelper', function (RecursionHelper) { 
    return { 
    template: '<div><div ng-click="hierarchyCtrl.ngModel.showChildren = !hierarchyCtrl.ngModel.showChildren">{{ hierarchyCtrl.ngModel.name }}</div><ul ng-if="hierarchyCtrl.ngModel.children && (hierarchyCtrl.ngModel.showChildren)"><li ng-repeat="element in hierarchyCtrl.ngModel.children"><hierarchy ng-model="element"></hierarchy></li></ul></div>', 
    restrict: 'E', 
    scope: { ngModel: '=' }, 
    controller: ['$scope', function($scope) { this.ngModel = $scope.ngModel; }], 
    controllerAs: 'hierarchyCtrl', 
    compile: function (element) { 
     return RecursionHelper.compile(element); 
    }, 
    }; 
}]); 

的index.html

<body> 
<h1>Hello Plunker!</h1> 
<div ng-controller="MainController as mainCtrl"> 
    <input type="text" ng-model="mainCtrl.search" ng-model-options="{debounce: 300}" ng-change="mainCtrl.filterHierarchies()" /> 
    <ul> 
    <li ng-repeat="hierarchy in mainCtrl.filteredHierarchies"><hierarchy ng-model="hierarchy"></hierarchy></li> 
    </ul> 
</div> 
</body> 

Plunker例如:https://plnkr.co/edit/1jiiiwkdUZY4tm7sm79F?p=preview

我就讓你寫的代碼部分,以突出匹配搜索,因爲它是很容易改變,做過濾功能的文本。提示:在函數中,您可以將htmlHighlighted屬性添加到您在<strong></strong>標記之間包裝匹配文本的每個節點。

由於這可能不是您正在尋找的確切行爲,因此您可以調整過濾器函數以在用戶更改其搜索時準確顯示您想要的內容。

一些代碼(遞歸助手)來自這個帖子:Recursion in Angular directives

+0

這應該是被接受的答案... –

+0

是的它的驚人。正在玩一點點。有一個問題,如果我不想顯示那些不符合搜索標準的孩子,那該如何實現。 @hilnius – otc

+1

當''''hierarchyiesFilter'''被調用時,在'''hierarchy'''指令模板中添加'''matches''''屬性的簡單方法id添加一個條件''' ng-show'''只有在他們'''MatchSearch'''或​​者你需要'''showChildren'''時才顯示孩子。 Forked plunker:https://plnkr.co/edit/h8vZQlbL47NpZgnaOB9f?p=preview 在這一點上,這只是純粹的算法,我最好的建議是你找到一張紙並圍繞你想要做的事情設計你的代碼。 – hilnius