Skip to content

Instantly share code, notes, and snippets.

@kindy
Created November 26, 2013 06:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kindy/7654167 to your computer and use it in GitHub Desktop.
Save kindy/7654167 to your computer and use it in GitHub Desktop.
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) {
deferred.reject(e);
$exceptionHandler(e);
}
if (!skipApply) $rootScope.$apply();
};
timeoutId = $browser.defer(debounced, delay);
// track id with method
methods[methodId].timeoutId = timeoutId;
cleanup = function(reason) {
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;
}]);
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.2/angular.min.js"></script>
<script src="app.js"></script>
<div ng-app='MyApp' ng-controller="MyCtrl">
<button ng-click="inc()">Add</button>
<p>{{ val }}</p>
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment