Skip to content

Instantly share code, notes, and snippets.

@alterx
Created February 6, 2015 20:42
Show Gist options
  • Save alterx/d7449b3f41215342cfda to your computer and use it in GitHub Desktop.
Save alterx/d7449b3f41215342cfda to your computer and use it in GitHub Desktop.
Debounce service for angularJS
// Modified version of http://jsfiddle.net/6K7Kd/68/ to support parameters, and inmediate execution
(function (/*window*/) {
'use strict';
function debounceService($rootScope, $browser, $q, $exceptionHandler) {
var deferreds = {},
methods = {},
uuid = 0;
function debounce(fn, delay, invokeApply, executeInmediately, params) {
var deferred = $q.defer(),
promise = deferred.promise,
skipApply = (angular.isDefined(invokeApply) && !invokeApply),
timeoutId, cleanup,
methodId, bouncing = false;
var debounced = function() {
if(deferreds[methods[methodId].timeoutId] && executeInmediately){
deferreds[methods[methodId].timeoutId].reject('canceled');
}
delete methods[methodId];
// If we are debouncing and executing at the end, resolve the promise here
if(!executeInmediately){
resolvePromise();
}
if (!skipApply){
$rootScope.$apply();
}
};
var resolvePromise = function() {
try {
deferred.resolve(fn.apply(this, params));
} catch(e) {
deferred.reject(e);
$exceptionHandler(e);
}
};
// 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;
}
});
if(!bouncing) {
// Not bouncing, then register new instance
methodId = uuid++;
methods[methodId] = {fn: fn};
// If we are debouncing and executing inmediately, resolve the promise here
if(executeInmediately){
resolvePromise();
}
} else {
// Clear the old timeout
if(deferreds[methods[methodId].timeoutId]){
deferreds[methods[methodId].timeoutId].reject('bounced');
}
$browser.defer.cancel(methods[methodId].timeoutId);
}
timeoutId = $browser.defer(debounced, delay);
// track id with method, we need this to clean it up later
methods[methodId].timeoutId = timeoutId;
cleanup = function() {
delete deferreds[promise.$$timeoutId];
};
promise.$$timeoutId = timeoutId;
deferreds[timeoutId] = deferred;
promise.then(cleanup, cleanup);
return promise;
}
// Similar to angular's $timeout cancel
debounce.cancel = function(promise) {
if (promise && promise.$$timeoutId in deferreds) {
deferreds[promise.$$timeoutId].reject('canceled');
return $browser.defer.cancel(promise.$$timeoutId);
}
return false;
};
return debounce;
}
module.factory('debounceService', ['$rootScope', '$browser', '$q', '$exceptionHandler', debounceService]);
})(window);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment