AngularJS Debounce Service
by Warspawn
HTML
<div ng-app='MyApp' ng-controller="MyCtrl">
<button ng-click="inc()">Add</button>
<p>{{ val }}</p>
</div>
JavaScript
angular.module('MyApp', [])
.controller('MyCtrl', ['$scope', '$debounce', function($scope, $debounce) {
$scope.val = 0;
$scope.inc = function() {
$debounce(increase, 300);
};
var increase = function() {
$scope.val++;
}
}])
// http://unscriptable.com/2009/03/20/debouncing-javascript-methods/
// adapted from angular's $timeout code
.factory('$debounce', ['$rootScope', '$browser', '$q', '$exceptionHandler',
function($rootScope, $browser, $q, $exceptionHandler) {
var deferreds = {},
methods = {},
uuid = 0;
function debounce(fn, delay, invokeApply) {
var deferred = $q.defer(),
promise = deferred.promise,
skipApply = (angular.isDefined(invokeApply) && !invokeApply),
timeoutId, cleanup,
methodId, bouncing = false;
// check we dont have this method already registered
angular.forEach(methods, function(value, key) {
if(angular.equals(methods[key].fn, fn)) {
bouncing = true;
methodId = key;
}
});
// not bouncing, then register new instance
if(!bouncing) {
methodId = uuid++;
methods[methodId] = {fn: fn};
} else {
// clear the old timeout
deferreds[methods[methodId].timeoutId].reject('bounced');
$browser.defer.cancel(methods[methodId].timeoutId);
}
var debounced = function() {
// actually executing? clean method bank
delete methods[methodId];
try {
deferred.resolve(fn());
} catch(e) {
...