149 votes

Comment mettre un retard sur AngularJS recherche instantanée ?

Je suis nouveau sur AngularJS, et j'ai un problème de performance que je n'arrive pas à résoudre. Je recherche instantanée mais c'est un peu de lag, car il commence à chercher sur chaque 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>

Les données JSON n'est pas le même que les grands, 300 KO seulement, je pense que ce dont j'ai besoin pour accomplir est de mettre un délai de ~1 sec sur la recherche d'attendre que l'utilisateur fini de taper, au lieu de l'exécution de l'action sur chaque frappe. AngularJS est-ce à l'interne, et après la lecture de docs et d'autres sujets ici, je ne pouvais pas trouver une réponse précise.

Je vous serais reconnaissant de tous les pointeurs sur comment je peux retarder la recherche instantanée. Merci.

301voto

Josue Ibarra Points 854

Mise à JOUR

Il est maintenant plus facile que jamais (Angulaire 1.3), il suffit d'ajouter un anti-rebond option sur le modèle.

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

Mise à jour plunker:
http://plnkr.co/edit/4V13gK

Documentation sur ngModelOptions:
https://docs.angularjs.org/api/ng/directive/ngModelOptions

Ancienne méthode:

Voici une autre méthode avec aucune dépendance angulaire au-delà de lui-même.

Vous avez besoin de définir un délai d'attente et de comparer votre chaîne avec la dernière version, si les deux sont le même, alors qu'il effectue la recherche.

$scope.$watch('searchStr', function (tmpStr)
{
  if (!tmpStr || tmpStr.length == 0)
    return 0;
  setTimeout(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);
});

et cela va dans votre point de vue:

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

<textarea> {{responseData}} </textarea>

Obligatoire plunker: http://plnkr.co/dAPmwf

122voto

Jason Aden Points 1299

Le problème ici est que la recherche sera exécutée à chaque fois les changements de modèle, qui est chaque keyup action sur l'entrée.

Il serait plus propre de façons de le faire, mais probablement le plus simple serait de basculer la liaison de sorte que vous avez un $champ d'application bien défini à l'intérieur de votre Contrôleur sur lequel votre filtre fonctionne. De cette façon, vous pouvez contrôler la fréquence de $portée de la variable est mise à jour. Quelque chose comme ceci:

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>

6voto

lgersman Points 278

Sans rebond / étranglé modèle des mises à jour pour angularjs : http://jsfiddle.net/lgersman/vPsGb/3/

Dans votre cas, il n'y a rien de plus à faire qu'à l'aide de la directive dans le jsfiddle code comme ceci:

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

C'est en fait un petit morceau de code composé d'une seule angulaire de la directive nommé "ng-ampère-anti-rebond" utilisant http://benalman.com/projects/jquery-throttle-debounce-plugin/ qui peut être attaché à un élément du dom. La directive réorganise les joints des gestionnaires d'événement de sorte qu'il peut contrôler quand à gaz événements.

Vous pouvez l'utiliser pour d'étranglement/anti-rebond * modèle angulaire des mises à jour * angulaire de gestionnaire d'événement ng-[event] * jquery gestionnaires d'événements

Jetez un oeil : http://jsfiddle.net/lgersman/vPsGb/3/

La directive sera une partie de la Orangevolt Ampère cadre (https://github.com/lgersman/jquery.orangevolt-ampere).

5voto

Daniel Popov Points 31

Je crois que la meilleure façon de résoudre ce problème est à l’aide de plugin de Ben Alman gaz jQuery / debounce. À mon avis, il est inutile de retarder les événements de chaque champ unique dans votre formulaire.

Juste envelopper votre $scope. $watch manipulation fonction dans $.debounce comme ceci :

3voto

dfsq Points 41491

Une autre solution consiste à ajouter une fonctionnalité de délai de mise à jour du modèle. La directive simple semble faire un truc :

Utilisation :

Donc il suffit d’utiliser au lieu de et décrivez désiré `` .

Démo : http://plnkr.co/edit/OmB4C3jtUD2Wjq5kzTSU?p=preview

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X