Могу ли я дебоширить или дросселировать наблюдаемый в AngularJS с помощью lodash?


у меня есть следующее, что делает часы на <input> поле, которое привязано к $scope.id. каждый раз при изменении значения поля ввода выполняется функция watch:

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

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

});

есть ли способ, которым я могу поставить тайм-аут на это или отменить это с _lodash, чтобы код не выполняется при каждом нажатии клавиши, пока пользователь изменяет значение.

что я хотел бы для задержка в одну секунду, так что после того, как пользователь перестал печатать на одну секунду, то этот блок кода внутри часов работает. Обратите внимание, что входное значение-это то, что может измениться в любой момент. Например, мне нужно вызвать функцию, если значение "1" или "10" или "1000". Это что-то похожее на то, как работает окно поиска с предложениями в Google. Если пользователь вводит 999, то мне нужно вызвать функцию. Если он удаляет 9, так что это 99, то мне нужно вызвать функцию.

у меня есть _lodash доступны, так что решение, которое использует, что может быть лучше подходит для моих нужд.

4 52

4 ответа:

это то, что вы ищете?

$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));

обратите внимание, однако, что если вы хотите изменить $scope внутри этой функции, вы должны обернуть его $scope.$apply(...) Как только _.debounce функция использует $timeout внутренне (что, насколько я понимаю, не делает) Angular не будет знать об изменениях, которые вы сделали на $scope.

обновление

что касается обновленного вопроса-да, вам нужно обернуть все тело функции обратного вызова с помощью

$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));

вы можете использовать ngModelOptions в угловой 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>

дополнительная информация:https://docs.angularjs.org/api/ng/directive/ngModelOptions

Я знаю, что вопрос просит решение лодашь. Во всяком случае, вот угловое решение:

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);
        };
    }; 
}); 

в контроллере:

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

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

});

вы можете инкапсулировать это в директиве. Источник: 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());
              });
          });
      }
  };
});