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

匿名 (未验证) 提交于 2019-12-03 01:12:01

问题:

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

$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.

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". This is something similar to the way the search box with suggestions works in Google. If the user types in 999 then I need the function to be called. If he deletes a 9 so it's 99 then I need the function to be called.

I do have _lodash available so a solution that uses that might be the best fit for my needs.

回答1:

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


回答2:

You can use ngModelOptions in Angular 1.3.0

HTML:

Name:
user.name = 

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



回答3:

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


回答4:

You can encapsulate this in a directive. Source: https://gist.github.com/tommaitland/7579618

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


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!