54

我有以下内容,它对<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

4 回答 4

80

您可以在 Angular 1.3.0 中使用 ngModelOptions

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

于 2014-06-25T06:27:47.760 回答
68

那是你要找的吗?

$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));
于 2014-01-13T11:50:34.780 回答
34

我知道这个问题需要一个 lodash 解决方案。无论如何,这是一个仅角度的解决方案:

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

});
于 2014-07-31T08:51:04.560 回答
6

您可以将其封装在指令中。来源: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());
              });
          });
      }
  };
});
于 2014-01-15T19:40:18.197 回答