AngularJSのインスタント検索にディレイをかけるには?

パフォーマンスに問題があり、解決できないでいます。インスタントサーチはありますが、keyup()のたびに検索を開始するので、ややラグがあります。

JS:

var App = angular.module('App', []);

App.controller('DisplayController', function($scope, $http) {
$http.get('data.json').then(function(result){
    $scope.entries = result.data;
});
});

HTMLです。

<input id="searchText" type="search" placeholder="live search..." ng-model="searchText" />
<div class="entry" ng-repeat="entry in entries | filter:searchText">
<span>{{entry.content}}</span>
</div>

JSONデータはそれほど大きくなく、300KBしかありません。私が達成しなければならないことは、キーストロークごとにアクションを実行するのではなく、ユーザーが入力を終えるのを待つために、検索に~1秒の遅延をかけることだと思います。AngularJSは内部的にこれを行っていますが、このサイトのドキュメントや他のトピックを読んでも、具体的な答えを見つけることができませんでした。

インスタント検索を遅らせるにはどうしたらいいのか、何かヒントをいただければ幸いです。

UPDATE(アップデイト

Angular 1.3では、モデルにデバウンスのオプションを追加するだけで、これまで以上に簡単にできるようになりました。

<input type="text" ng-model="searchStr" ng-model-options="{debounce: 1000}">

プランカーを更新しました。 http://plnkr.co/edit/4V13gK

ngModelOptionsに関するドキュメントです。
https://docs.angularjs.org/api/ng/directive/ngModelOptions

**古い方法ですが

angular本体以外の依存関係がない別の方法を紹介します。

タイムアウトを設定し、現在の文字列と過去のバージョンを比較して、両方が同じであれば検索を実行します。

$scope.$watch('searchStr', function (tmpStr)
{
  if (!tmpStr || tmpStr.length == 0)
    return 0;
   $timeout(function() {

    // if searchStr is still the same..
    // go ahead and retrieve the data
    if (tmpStr === $scope.searchStr)
    {
      $http.get('//echo.jsontest.com/res/'+ tmpStr).success(function(data) {
        // update the textarea
        $scope.responseData = data.res; 
      });
    }
  }, 1000);
});

と表示され、これがビューに入ります。


<input type="text" data-ng-model="searchStr">

<textarea> {{responseData}} 
解説 (7)
ソリューション

(Angular 1.3の解決策は以下の回答を参照してください)。

ここでの問題は、モデルが変更されるたびに検索が実行されることで、それは入力に対するすべてのキーアップアクションです。

もっとすっきりとした方法があると思いますが、おそらく最も簡単な方法は、フィルタが動作するコントローラ内で定義された$scopeプロパティを持つようにバインディングを変更することでしょう。そうすれば、$scope 変数の更新頻度を制御することができます。以下のような感じです。

JS:

var App = angular.module('App', []);

App.controller('DisplayController', function($scope, $http, $timeout) {
    $http.get('data.json').then(function(result){
        $scope.entries = result.data;
    });

    // This is what you will bind the filter to
    $scope.filterText = '';

    // Instantiate these variables outside the watch
    var tempFilterText = '',
        filterTextTimeout;
    $scope.$watch('searchText', function (val) {
        if (filterTextTimeout) $timeout.cancel(filterTextTimeout);

        tempFilterText = val;
        filterTextTimeout = $timeout(function() {
            $scope.filterText = tempFilterText;
        }, 250); // delay 250 ms
    })
});

HTMLです。

<input id="searchText" type="search" placeholder="live search..." ng-model="searchText" />
<div class="entry" ng-repeat="entry in entries | filter:filterText">
    <span>{{entry.content}}</span>
</div>
解説 (4)

debounced / throttled model updates for angularjs : http://jsfiddle.net/lgersman/vPsGb/3/

あなたのケースでは、jsfiddleのコードで以下のようにディレクティブを使用する以外にはありません。

<input 
    id="searchText" 
    type="search" 
    placeholder="live search..." 
    ng-model="searchText" 
    ng-ampere-debounce
/>

基本的には、 http://benalman.com/projects/jquery-throttle-debounce-plugin/ を利用した "ng-ampere-debounce" という名前の angular ディレクティブ1つで構成される小さなコードで、任意の dom 要素にアタッチすることができます。このディレクティブは、アタッチされたイベントハンドラの順番を入れ替えて、イベントをスロットルするタイミングを制御することができます。

次のような用途に使用できます。

  • モデル アンギュラーアップデート angular イベントハンドラ ng-[event] * angular イベントハンドラ ng-[event
  • jquery イベントハンドラー

ご覧ください: http://jsfiddle.net/lgersman/vPsGb/3/

このディレクティブはOrangevolt Ampereフレームワーク(https://github.com/lgersman/jquery.orangevolt-ampere)の一部になります

解説 (0)