Can I debounce or throttle a watched <input> in AngularJS using _lodash?
Solution 1:
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
Solution 2:
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));
Solution 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));
});
Solution 4:
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());
});
});
}
};
});