2013-07-31 5 views
33

AngularJSの項目名のリストに対して単純な<input>検索フィルターが設定されています。AngularJS 'ng-filter'は〜1000個の要素の配列で非常に遅いです

var uniqueLists = { 
    category1: ['item1', 'item2', 'item3' ... 'item180' ], // Real list contains ~180 items 
    category2: ['itemA', 'itemB', 'itemC' ... 'itemZZZ' ], // Real list contains ~1080 items 
    category3: ['otheritem1', 'otheritem2', 'otheritem3' ] // Real list contains 6 items 
    } 

私は角にこのリストを反復処理し、各カテゴリの<ul>で結果をプリントアウト:

私のリストは次のようになります。明確にするために

<div ng-repeat="(key,val) in uniqueLists"> 
    <form ng-model="uniqueLists[index][0]"> 
     <input ng-model="searchFilter" type="text" /> 
      <ul> 
       <li ng-repeat="value in val | filter: searchFilter"> 
        <label> 
         <input type="checkbox" ng-model="selectedData[key][value]" /> 
         {{value}} 
        </label> 
       </li> 
      </ul> 
    </form> 
</div> 

、selectedDataは次のようになります。filterも私の非常に高速のコンピューター上で、非常にラグがあるが

var selectedData = {category1: [item1:true], category2: [], category3: []); // if 'item1's checkbox is checked. 

このリストに、うまく働いています。入力に文字を入力すると、リストが更新されるのに1〜2秒かかります。

私は一度に約1000個のアイテムをフィルタリングしている可能性が高いと認識していますが、他の場所でこれについての議論はありませんでした。

フィルタのパフォーマンスを向上させる方法はありますか?

+0

あなたのコードでjsfiddle本当にこの場合に役立ちます。また、私は、ループ内のループを持っていることを想像することができますし、フィルタはかなりです、私はまた、最初のループの内部にフォームを作成しています。 jsffidleは本当に助けてくれるでしょう; – dcodesmith

答えて

52

フィルタアプローチの主な問題は、各時にDOMを操作するので、それは遅いですが、フィルタの影響はありませんされて変化していることです。代わりに、次のようなものを使用することもできます。

ng-show="([item] | filter:searchFilter).length > 0" 

更新http://jsbin.com/xajehulo/1/


  • フィルタ:http://jsbin.com/fuwadanu/1/
  • NG-ショー@OverZealousからいくつかのコードを貸す

    、あなたは行動を比較するために、以下のように使用することができます:Angular v1.2ではtrack byの構文が使用されました。このような問題にも役立ちます。要素はいくつかのユニークな属性を持って提供し、一つは使用することができます。

    item.idはすべての項目で一意である必要があり
    ng-repeat="item in items | filter:searchFilter track by item.id" 
    

    を。 track byとすると、最後のリストに含まれていないDOM要素のみが削除され、残りの部分はと記憶されます。となります。一方、track byがない場合、全体リストはredrawn毎回です。一言で言えば、DOM操作はずっと少なくなり、再描画はより速くなります。

+2

本当にありがとうございます。 –

+0

これは答えになるはずです。これはとてもうまくいって、私はそれを信じられませんでした! –

+0

ng-showの速度向上は本当に印象的です。説明ありがとうございました –

4

キー入力を押すたびに、すべてのウォッチ式を実行する必要があり、たくさんのコードを見る必要があります。項目名は不変で 場合、あなたは書くことができますたとえばhttps://github.com/abourget/abourget-angularのために使用することができます

<label> 
    <input type="checkbox" ng-model="selectedData[key][value]" /> 
    <span set-text='value'></span> 
</label> 

そして、あなたは、各キーストロークで実行する1000のより少ないウォッチ式を持っています。

また、最後のキーストロークから500ms後にトリガーをフィルタリングするために、ある種のスロットル入力を使用することができます。高速だが超高速ではありません、私のコンピュータで、

5

I created a fiddle to simulate (part of) the code you are showing.

、許容できるだけでなく実行されます。それは少し遅いですが、それはチェックボックスとの双方向バインディングを持っている過度に長いリストをフィルタリングしています。文字を入力するたびに、リスト全体をスキャンし、項目を削除(または追加)する必要があります。

私はこれを解決するための最善の策は、this StackOverflow答えに示すように、単純なページネーションのいくつかの並べ替えを追加することだと思います。

Here I've modified my example to include pagination次/前より優れたソリューションに投資したいと思うかもしれませんが、すべてを一度にすべて表示しないと、結果が非​​常に速くなる可能性があります。それでもリスト全体を検索しますが、レンダリングされたリストははるかに制限されています。

追加:

コントローラにスコープにページング情報を追加します。

$scope.currentPage = 0; 
$scope.pageSize = 20; 
$scope.numberOfPages = function() { 
    return Math.ceil($scope.items.length/$scope.pageSize); 
} 

は、特定のページから開始するように新しいフィルタを作成します。

app.filter('startFrom', function() { 
    return function (input, start, pageSize) { 
     start = +start; //parse to int 
     pageSize = +pageSize; 
     while (start > input.length) { 
      start -= pageSize; 
     } 
     if (start < 0) { 
      start = 0; 
     } 
     return input.slice(start); 
    }; 
}); 

はにフィルタを追加します。リストを制限するビュー:

<li ng-repeat="value in items | filter:searchFilter | 
     startFrom:currentPage*pageSize:pageSize | limitTo:pageSize"> 

は、ページに改ページボタンを追加します:

<div> 
     <button ng-disabled="currentPage == 0" ng-click="currentPage=currentPage-1">Previous</button> {{ currentPage+1 }}/{{ numberOfPages() }} 
     <button ng-disabled="currentPage >= items.length/pageSize - 1" ng-click="currentPage=currentPage+1">Next</button> 
    </div> 
4

ます。また、 "limitTo" フィルタを使用して表示される項目を制限することができます。これにより、モデル内に膨大な数のアイテムが除外されますが、DOM内のすべてのアイテムを表示しようとしていないため、遅くなることはありません。ここで

は、以前の回答に基づいて修正さjsbinですが、limitToフィルタを適用:

http://jsbin.com/IhOcaKo/1

+0

この場合、あなたは結果を隠すだろうか? –

19

もう一つの興味深い最適化は一定の時間まで、モデルチェンジ「をトリガしない」ことです。NG-モデルオプション=「{デバウンス:500}」

500msの間にユーザストップタイピング場合、これは、フィルタをトリガする検索入力フィールドにこれを追加

私は上記のフィドル更新:いいえソリューションが私のために動作しませ

http://jsfiddle.net/CXBN4/14/

<input ng-model="searchFilter" type="text" ng-model-options="{debounce: 500}" /> 
+0

ng-changeと組み合わせて使用​​する場合は、こちらをご覧ください: https://stackoverflow.com/questions/26446681/angular-ng-change-delay – Fabio

0

を:(

最後に、私ははこの方法だけで問題を解決しよう:

<li ng-repeat="value in val | filter: searchFilter | limitTo:200"> 

解決される... :)

関連する問題