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

前端 未结 4 1152
长发绾君心
长发绾君心 2020-12-08 03:54

I have the following which does a watch on an field that\'s bound to $scope.id. Every time the input field value changes the watch function gets e

相关标签:
4条回答
  • 2020-12-08 04:21

    You can encapsulate this in a 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());
                  });
              });
          }
      };
    });
    
    0 讨论(0)
  • 2020-12-08 04:30

    You can use ngModelOptions in 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>
    

    More Info: https://docs.angularjs.org/api/ng/directive/ngModelOptions

    0 讨论(0)
  • 2020-12-08 04:42

    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.

    UPDATE

    As to the updated question - yes you need to wrap the entire callback function body with

    $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));
    
    0 讨论(0)
  • 2020-12-08 04:46

    I know the question asks for a lodash solution. 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));
    
    });
    
    0 讨论(0)
提交回复
热议问题