web-dev-qa-db-fra.com

Puis-je faire rebondir ou étrangler une <entrée> surveillée dans AngularJS en utilisant lodash?

J'ai ce qui suit qui fait une montre sur un <input> champ lié à $ scope.id. Chaque fois que la valeur du champ d'entrée change, la fonction de surveillance est exécutée:

$scope.$watch("id", function (id) {

   // code that does something based on $scope.id

});

Existe-t-il un moyen de mettre un délai d'attente à ce sujet ou de le rebondir avec _lodash afin que le code ne s'exécute pas à chaque pression de touche pendant que l'utilisateur modifie la valeur.

Ce que je voudrais, c'est pour un délai d'une seconde afin qu'après que l'utilisateur ait arrêté de taper pendant une seconde, le bloc de code à l'intérieur de la montre s'exécute. Notez que la valeur d'entrée peut changer à tout moment. Par exemple, j'ai besoin que la fonction soit appelée si la valeur est "1" ou "10" ou "1000". C'est quelque chose de similaire à la façon dont le champ de recherche avec des suggestions fonctionne dans Google. Si l'utilisateur tape 999, j'ai besoin que la fonction soit appelée. S'il supprime un 9 alors c'est 99 alors j'ai besoin que la fonction soit appelée.

J'ai _lodash disponible donc une solution qui utilise qui pourrait être le mieux adapté à mes besoins.

52
user1943020

C'est ça que tu cherches?

$scope.$watch("id", _.debounce(function (id) {
    // Code that does something based on $scope.id
    // This code will be invoked after 1 second from the last time 'id' has changed.
}, 1000));

Notez, cependant, que si vous voulez changer $ scope à l'intérieur de cette fonction, vous devez l'envelopper $scope.$apply(...) comme si la fonction _.debounce N'utilise pas $timeout En interne (ce que je comprends) il ne fait pas) Angular ne sera pas au courant des changements que vous avez faits sur le $scope.

MISE À JOUR

En ce qui concerne la question mise à jour - oui, vous devez envelopper le corps entier de la fonction de rappel avec

$scope.$apply():

$scope.$watch("id", _.debounce(function (id) {
    // This code will be invoked after 1 second from the last time 'id' has changed.
    $scope.$apply(function(){
        // Code that does something based on $scope.id
    })
}, 1000));
66
Alex Vayda

Vous pouvez utiliser ngModelOptions dans Angular 1.3.0

HTML:

<div ng-controller="Ctrl">
  <form name="userForm">
    Name:
    <input type="text" name="userName"
           ng-model="user.name"
           ng-model-options="{ debounce: 1000 }" />
    <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button><br />
  </form>
  <pre>user.name = <span ng-bind="user.name"></span></pre>
</div>

Plus d'informations: https://docs.angularjs.org/api/ng/directive/ngModelOptions

80
AhmedRiyad

Je sais que la question demande une solution de lodash. Quoi qu'il en soit, voici une solution angular uniquement:

app.factory('debounce', function($timeout) {
    return function(callback, interval) {
        var timeout = null;
        return function() {
            $timeout.cancel(timeout);
            var args = arguments;
            timeout = $timeout(function () { 
                callback.apply(this, args); 
            }, interval);
        };
    }; 
}); 

Dans le contrôleur:

app.controller('BlaCtrl', function(debounce) {

    $scope.$watch("id", debounce(function (id) {
        ....
    }, 1000));

});
33
jdachtera

Vous pouvez l'encapsuler dans une directive. Source: https://Gist.github.com/tommaitland/7579618

<input type="text" ng-model="id" ng-debounce="1000">

Javascript

app.directive('ngDebounce', function ($timeout) {
  return {
      restrict: 'A',
      require: 'ngModel',
      priority: 99,
      link: function (scope, Elm, attr, ngModelCtrl) {
          if (attr.type === 'radio' || attr.type === 'checkbox') {
              return;
          }

          var delay = parseInt(attr.ngDebounce, 10);
          if (isNaN(delay)) {
              delay = 1000;
          }

          Elm.unbind('input');

          var debounce;
          Elm.bind('input', function () {
              $timeout.cancel(debounce);
              debounce = $timeout(function () {
                  scope.$apply(function () {
                      ngModelCtrl.$setViewValue(Elm.val());
                  });
              }, delay);
          });
          Elm.bind('blur', function () {
              scope.$apply(function () {
                  ngModelCtrl.$setViewValue(Elm.val());
              });
          });
      }
  };
});
6
jessegavin