Retard angulaire de changement de ng

117

J'ai une entrée qui filtre une liste ng-répétée en cas de changement. La répétition contient beaucoup de données et prend quelques secondes pour tout filtrer. Je voudrais qu'il y ait un délai de 0,5 seconde avant de commencer le processus de filtrage. Quelle est la bonne manière angulaire pour créer ce retard?

Contribution

 <input ng-model="xyz" ng-change="FilterByName()" />

Répéter

 <div ng-repeat"foo in bar">
      <p>{{foo.bar}}</p>
 </div>

Fonction de filtre

 $scope.FilterByName = function () {
      //Filtering Stuff Here
 });

Merci

MGot90
la source
1
Utilisez simplement un $timeoutpendant 500 ms. $scope.FilterByName = function () { $timeout(_filterByName , 500)
PSL
@PSL où dans la fonction? Je souhaite que la recherche ne s'exécute qu'une seule fois. Si je viens de le compenser, cela ne fera que créer un plus grand délai et effectuer plusieurs recherches.
MGot90
Ouais, dans ta fonction. Le commentaire précédent contient un extrait. Vous pouvez utiliser $timeout.cancel(timeoutpromise)si un délai d'expiration est en cours et qu'une autre modification est déclenchée.
PSL
1
@PSL Merci fonctionne comme un charme!
MGot90

Réponses:

274

AngularJS 1.3+

Depuis AngularJS 1.3, vous pouvez utiliser la debouncepropriété ngModelOptionsfournit pour y parvenir très facilement sans utiliser $timeoutdu tout. Voici un exemple:

HTML:

<div ng-app='app' ng-controller='Ctrl'>
    <input type='text' placeholder='Type a name..'
        ng-model='vm.name'
        ng-model-options='{ debounce: 1000 }'
        ng-change='vm.greet()'
    />

    <p ng-bind='vm.greeting'></p>
</div>

JS:

angular.module('app', [])
.controller('Ctrl', [
    '$scope',
    '$log',
    function($scope, $log){
        var vm = $scope.vm = {};

        vm.name = '';
        vm.greeting = '';
        vm.greet = function greet(){
            vm.greeting = vm.name ? 'Hey, ' + vm.name + '!' : '';
            $log.info(vm.greeting);
        };
    }
]);

-- OU --

Vérifiez le violon

Avant AngularJS 1.3

Vous devrez utiliser $ timeout pour ajouter un délai et probablement avec l'utilisation de $ timeout.cancel (previoustimeout), vous pouvez annuler tout timeout précédent et exécuter le nouveau (aide à empêcher le filtrage d'être exécuté plusieurs fois consécutivement dans un intervalle de temps)

Voici un exemple:

app.controller('MainCtrl', function($scope, $timeout) {
    var _timeout;

    //...
    //...

    $scope.FilterByName = function() {
        if(_timeout) { // if there is already a timeout in process cancel it
            $timeout.cancel(_timeout);
        }
        _timeout = $timeout(function() {
            console.log('filtering');
            _timeout = null;
        }, 500);
    }
});
rckd
la source
2
Notez que cela ng-model-optionsn'a été ajouté que dans Angular v1.3 (et la propriété anti- rebond en beta.8 ). Ceux qui ont encore besoin d'utiliser une ancienne version d'Angular devront recourir à d'autres solutions, comme celle de PSL, ou en utilisant un module externe comme ng-debounce .
Vincent Sels
Un inconvénient pourrait être que cela semble également retarder les validations comme ng-pattern.
Johan Baaij
19

Vous pouvez utiliser $timeoutpour ajouter un délai et probablement avec l'utilisation de $timeout.cancel(previoustimeout)vous pouvez annuler tout délai d'expiration précédent et exécuter le nouveau (aide à empêcher le filtrage d'être exécuté plusieurs fois consécutivement dans un intervalle de temps)

Exemple:-

app.controller('MainCtrl', function($scope, $timeout) {
  var _timeout;

 //...
 //...

  $scope.FilterByName = function () {
    if(_timeout){ //if there is already a timeout in process cancel it
      $timeout.cancel(_timeout);
    }
    _timeout = $timeout(function(){
      console.log('filtering');
      _timeout = null;
    },500);
  }
 });

Plnkr

PSL
la source
8
Pour le downvoter et les futurs visiteurs: Cette réponse a été ajoutée pour Angular 1.2.x , et ajoutée probablement avant la sortie de 1.3.x qui a l'option anti-rebond avec ng-model-options et n'a jamais eu la chance de réviser la réponse avant une meilleure La réponse de @rckd est arrivée (environ 3 mois après celle-ci).
PSL
4
Même si j'utilise angular js 1.4, je trouve toujours la solution $ timeout utile ng-changelorsque je ne veux pas rebondir le modèle.
SStanley
8

Je sais que la question est trop ancienne. Mais je veux toujours fournir un moyen plus rapide d'y parvenir en utilisant le débouncing .

Ainsi, le code peut être écrit comme

<input ng-model="xyz" ng-change="FilterByName()" ng-model-options="{debounce: 500}"/>

Le debounce prendra le nombre en millisecondes.

Naibedya Kar
la source
0

ou vous pouvez utiliser la directive 'typeahead-wait-ms = "1000"' de angular-ui

<input 
   typeahead="name for name in filterWasChanged()"
   typeahead-wait-ms="1000"
   type="text" placeholder="search"
   class="form-control" style="text-align: right" 
   ng-model="templates.model.filters.name">
Vadym Kaptan
la source