Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

Commit

Permalink
chore(debounce): create debounce helper
Browse files Browse the repository at this point in the history
- Create internal debounce helper
- Move debounce logic from typeahead to use helper

Closes #3966
Closes #4813
  • Loading branch information
wesleycho committed Nov 3, 2015
1 parent aff9010 commit 73efc78
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 19 deletions.
21 changes: 21 additions & 0 deletions src/debounce/debounce.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
angular.module('ui.bootstrap.debounce', [])
/**
* A helper, internal service that debounces a function
*/
.factory('$$debounce', ['$timeout', function($timeout) {
return function(callback, debounceTime) {
var timeoutPromise;

return function() {
var self = this;
var args = Array.prototype.slice(arguments);
if (timeoutPromise) {
$timeout.cancel(timeoutPromise);
}

timeoutPromise = $timeout(function() {
callback.apply(self, args);
}, debounceTime);
};
};
}]);
40 changes: 40 additions & 0 deletions src/debounce/test/debounce.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
describe('$$debounce', function() {
var $$debounce, $timeout, debouncedFunction, i;

beforeEach(module('ui.bootstrap.debounce'));
beforeEach(inject(function(_$$debounce_, _$timeout_) {
$$debounce = _$$debounce_;
$timeout = _$timeout_;
i = 0;
debouncedFunction = $$debounce(function() {
i++;
}, 100);
}));

it('should function like a $timeout when called once during timeout', function() {
debouncedFunction();
$timeout.flush(50);

expect(i).toBe(0);

$timeout.flush(50);

expect(i).toBe(1);
});

it('should only execute 100ms after last call when called twice', function() {
debouncedFunction();
$timeout.flush(50);

expect(i).toBe(0);

debouncedFunction();
$timeout.flush(50);

expect(i).toBe(0);

$timeout.flush(50);

expect(i).toBe(1);
});
});
33 changes: 14 additions & 19 deletions src/typeahead/typeahead.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.debounce', 'ui.bootstrap.position'])

/**
* A helper service that can parse typeahead's syntax (string provided by users)
Expand Down Expand Up @@ -26,8 +26,8 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
};
}])

.controller('UibTypeaheadController', ['$scope', '$element', '$attrs', '$compile', '$parse', '$q', '$timeout', '$document', '$window', '$rootScope', '$uibPosition', 'uibTypeaheadParser',
function(originalScope, element, attrs, $compile, $parse, $q, $timeout, $document, $window, $rootScope, $position, typeaheadParser) {
.controller('UibTypeaheadController', ['$scope', '$element', '$attrs', '$compile', '$parse', '$q', '$timeout', '$document', '$window', '$rootScope', '$$debounce', '$uibPosition', 'uibTypeaheadParser',
function(originalScope, element, attrs, $compile, $parse, $q, $timeout, $document, $window, $rootScope, $$debounce, $position, typeaheadParser) {
var HOT_KEYS = [9, 13, 27, 38, 40];
var eventDebounceTime = 200;
var modelCtrl, ngModelOptions;
Expand Down Expand Up @@ -264,8 +264,16 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
$document.find('body').bind('scroll', fireRecalculating);
}

// Declare the timeout promise var outside the function scope so that stacked calls can be cancelled later
var timeoutEventPromise;
// Declare the debounced function outside recalculating for
// proper debouncing
var debouncedRecalculate = $$debounce(function() {
// if popup is visible
if (scope.matches.length) {
recalculatePosition();
}

scope.moveInProgress = false;
}, eventDebounceTime);

// Default progress type
scope.moveInProgress = false;
Expand All @@ -276,20 +284,7 @@ angular.module('ui.bootstrap.typeahead', ['ui.bootstrap.position'])
scope.$digest();
}

// Cancel previous timeout
if (timeoutEventPromise) {
$timeout.cancel(timeoutEventPromise);
}

// Debounced executing recalculate after events fired
timeoutEventPromise = $timeout(function() {
// if popup is visible
if (scope.matches.length) {
recalculatePosition();
}

scope.moveInProgress = false;
}, eventDebounceTime);
debouncedRecalculate();
}

// recalculate actual position and set new values to scope
Expand Down

0 comments on commit 73efc78

Please sign in to comment.