简体   繁体   English

我可以使用_lodash去抖动或限制AngularJS中的<input>吗?

[英]Can I debounce or throttle a watched <input> in AngularJS using _lodash?

I have the following which does a watch on an <input> field that's bound to $scope.id. 我有以下内容监视绑定到$ scope.id的<input>字段。 Every time the input field value changes the watch function gets executed: 每次输入字段值改变时,执行watch函数:

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

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

});

Is there a way I can put a timeout on this or debounce this with _lodash so that the code does not execute on each keypress while the user is changing the value. 有没有办法可以对此进行超时或者使用_lodash进行去抖动,以便在用户更改值时代码不会在每个按键上执行。

What I would like is for a delay of one second so that after the user has stopped typing for one second then the code block inside the watch runs. 我想要的是延迟一秒钟,以便在用户停止输入一秒后,手表内的代码块运行。 Note that the input value is something that could change at any time. 请注意,输入值可能随时发生变化。 For example I need the function to be called if the value is "1" or "10" or "1000". 例如,如果值为“1”或“10”或“1000”,我需要调用该函数。 This is something similar to the way the search box with suggestions works in Google. 这与带有建议的搜索框在Google中的工作方式类似。 If the user types in 999 then I need the function to be called. 如果用户键入999,那么我需要调用该函数。 If he deletes a 9 so it's 99 then I need the function to be called. 如果他删除了9,那么它就是99,那么我需要调用该函数。

I do have _lodash available so a solution that uses that might be the best fit for my needs. 我确实有_lodash可用,因此使用它的解决方案可能最适合我的需求。

You can use ngModelOptions in Angular 1.3.0 您可以在Angular 1.3.0中使用ngModelOptions

HTML: 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>

More Info: https://docs.angularjs.org/api/ng/directive/ngModelOptions 更多信息: https//docs.angularjs.org/api/ng/directive/ngModelOptions

Is that what are you looking for? 那你在找什么?

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

Note, however, that if you want to change $scope inside that function you should wrap it $scope.$apply(...) as unless _.debounce function uses $timeout internally (which as far as I understand it doesn't do) Angular will not be aware of the changes you did on the $scope . 但是请注意,如果要在该函数内部更改$ scope,则应将其包装为$scope.$apply(...) as除非_.debounce函数在内部使用$timeout (据我所知,它不会do)Angular不会意识到你在$scope上所做的更改。

UPDATE UPDATE

As to the updated question - yes you need to wrap the entire callback function body with 至于更新的问题 - 是的,你需要包装整个回调函数体

$scope.$apply() : $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));

I know the question asks for a lodash solution. 我知道这个问题需要一个lodash解决方案。 Anyway here is an angular only solution: 无论如何这里只是一个角度解决方案:

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

In the controller: 在控制器中:

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

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

});

You can encapsulate this in a directive. 您可以将其封装在指令中。 Source: https://gist.github.com/tommaitland/7579618 资料来源: https//gist.github.com/tommaitland/7579618

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

Javascript 使用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());
              });
          });
      }
  };
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM