46 votes

Comment écrire un service anti-rebond dans AngularJS

La bibliothèque de soulignement fournit une fonction anti-rebond qui empêche plusieurs appels à une fonction dans une période de temps définie. Leur version utilise setTimeout.

Comment pourrions-nous faire cela en pur code AngularJS?

De plus, pouvons-nous utiliser les promesses de style $ q pour récupérer la valeur de retour de la fonction appelée après la période de rebond?

90voto

Pete BD Points 4774

Voici un exemple de fonctionnement d'un tel service: http://plnkr.co/edit/fJwRER?p=preview. Il crée un $q différée objet qui sera résolu lorsque le sans rebond fonction est finalement appelé.

Chaque fois que l' debounce fonction est appelée la promesse pour le prochain appel de la fonction interne est retourné.

// Create an AngularJS service called debounce
app.factory('debounce', ['$timeout','$q', function($timeout, $q) {
  // The service is actually this function, which we call with the func
  // that should be debounced and how long to wait in between calls
  return function debounce(func, wait, immediate) {
    var timeout;
    // Create a deferred object that will be resolved when we need to
    // actually call the func
    var deferred = $q.defer();
    return function() {
      var context = this, args = arguments;
      var later = function() {
        timeout = null;
        if(!immediate) {
          deferred.resolve(func.apply(context, args));
          deferred = $q.defer();
        }
      };
      var callNow = immediate && !timeout;
      if ( timeout ) {
        $timeout.cancel(timeout);
      }
      timeout = $timeout(later, wait);
      if (callNow) {
        deferred.resolve(func.apply(context,args));
        deferred = $q.defer();
      }
      return deferred.promise;
    };
  };
}]);

Vous obtenez la valeur de retour de la sans rebond de la fonction en utilisant la méthode de la promesse.

$scope.logReturn = function(msg) {
  var returned = debounce($scope.addMsg, 2000, false);
  console.log('Log: ', returned);
  returned.then(function(value) {
    console.log('Resolved:', value);
  });
};

Si vous appelez logReturn plusieurs fois en succession rapide, vous verrez la promesse connecté sur et sur, mais un seul résolu message.

50voto

superluminary Points 5496

Angulaire 1.3 a antirebond standard

La peine de mentionner que d'anti-rebond est intégré dans Angulaire 1.3. Comme vous pouvez vous attendre, il a mis en œuvre une directive. Vous pouvez faire ceci:

<input ng-model='address' ng-model-options="{ debounce: 500 }" />

Comme vous vous y attendez le $scope.l'adresse n'est pas mis à jour jusqu'à 500 ms après la dernière frappe.

Si vous avez besoin de plus de contrôle

Si vous voulez plus de précision, vous pouvez définir différents rebondir fois pour différents événements:

<input ng-model='person.address' ng-model-options="{ updateOn: 'default blur', debounce: {'default': 500, 'blur': 0} }" />

Ici par exemple, nous avons un 500ms de rebond pour une séquence de touches, et aucun rebond pour un flou.

La Documentation

Lire la documentation ici: https://docs.angularjs.org/api/ng/directive/ngModelOptions

31voto

Roy Truelove Points 6532

Depuis que j'ai écrit les commentaires ci-dessus, j'ai un peu changé d'avis à ce sujet.

La réponse courte est que vous ne devriez pas avoir besoin de rebondir les fonctions qui renvoient des valeurs.

Pourquoi? Eh bien, philosophiquement, je pense qu'il est plus logique de continuer à rebondir pour les événements et uniquement pour les événements. Si vous avez une méthode qui retourne une valeur que vous souhaitez rebounce, vous devez plutôt rebounce l' événement qui provoque l'exécution de votre méthode en aval.

7voto

Leblanc Meneses Points 1664

Pete BD a donné un bon départ pour l'anti-rebond service, cependant, je vois deux problèmes:

  1. retourne lorsque vous devez envoyer à un travail() rappel qui utilise javascript fermeture si vous avez besoin de changer d'état en l'appelant.
  2. délai d'attente variable n'est pas que le délai d'attente variable d'un problème? timeout[] peut-être? imaginez 2 à l'aide de directives anti-rebond - signalr, entrée validateur de formulaire, - je crois que l'usine approche était en panne.

Ce que je suis actuellement en utilisant:

J'ai changé d'usine, de service, de sorte que chaque directive obtient une NOUVELLE instance de l'anti-rebond aka nouvelle instance du délai variable. - je n'ai pas couru dans une situation où 1 directive aurez besoin de délai d'attente pour être timeout[].

    .service('reactService', ['$timeout', function ($timeout) {
    var timeout;

    this.Debounce = function (func, wait, immediate) {
        var context = this, args = arguments;
        var later = function () {
            timeout = null;
            if (!immediate) {
                func.apply(context, args);
            }
        };
        var callNow = immediate && !timeout;
        if (timeout) {
            $timeout.cancel(timeout);
        }
        timeout = $timeout(later, wait);
        if (callNow) {
            func.apply(context, args);
        }
    };
}]);

dans mon angularjs à distance du programme de validation

    .directive('remoteValidator', ['$http', 'reactService', function ($http, reactService) {
        return {
            require: 'ngModel',
            link: function (scope, elm, attrs, ctrl) {

                var work = function(){
//....
                };

                elm.on('blur keyup change', function () {
                   reactService.Debounce(function(){ scope.$apply(work); }, 1000, false);
                });
            }
        };
    }])

2voto

Shahar Talmi Points 1

Il existe une bonne implémentation à la fois d'un service anti-rebond et d'une directive pouvant fonctionner avec n'importe quel modèle ng sur: https://github.com/shahata/angular-debounce

Ou installez-le simplement en utilisant:

 bower install ng-debounce
 

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