Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write a debounce service in AngularJS

Tags:

angularjs

The underscore library provides a debounce function that prevents multiple calls to a function within a set period of time. Their version makes use of setTimeout.

How could we do this in pure AngularJS code?

Moreover, can we make use of $q style promises to retrieve the return value from the called function after the debounce period?

like image 764
Pete BD Avatar asked Nov 10 '12 06:11

Pete BD


People also ask

What is debounce in Angularjs?

debounce : integer value which contains the debounce model update value in milliseconds. A value of 0 triggers an immediate update. If an object is supplied instead, you can specify a custom value for each event. For example: ng-model-options="{ updateOn: 'default blur', debounce: { 'default': 500, 'blur': 0 } }"

What is debounce and how could you implement debounce?

The debounce() function forces a function to wait a certain amount of time before running again. The function is built to limit the number of times a function is called. The Send Request() function is debounced. Requests are sent only after fixed time intervals regardless of how many times the user presses the button.

What is Debouncing a request?

Debouncing allows us to call a function after a certain amount of time has passed. This is very useful to avoid unnecessary API calls to the server If you're making an API call for every character typed in the input text. Let's understand this by writing some code.


2 Answers

Here is a working example of such a service: http://plnkr.co/edit/fJwRER?p=preview. It creates a $q deferred object that will be resolved when the debounced function is finally called.

Each time the debounce function is called the promise to the next call of the inner function is returned.

// Create an AngularJS service called debounce app.factory('debounce', ['$timeout','$q', function($timeout, $q) {   // The service is actually this function, which we call with the func   // that should be debounced and how long to wait in between calls   return function debounce(func, wait, immediate) {     var timeout;     // Create a deferred object that will be resolved when we need to     // actually call the func     var deferred = $q.defer();     return function() {       var context = this, args = arguments;       var later = function() {         timeout = null;         if(!immediate) {           deferred.resolve(func.apply(context, args));           deferred = $q.defer();         }       };       var callNow = immediate && !timeout;       if ( timeout ) {         $timeout.cancel(timeout);       }       timeout = $timeout(later, wait);       if (callNow) {         deferred.resolve(func.apply(context,args));         deferred = $q.defer();       }       return deferred.promise;     };   }; }]); 

You get the return value from the debounced function by using the then method on the promise.

$scope.addMsg = function(msg) {     console.log('addMsg called with', msg);     return msg; };  $scope.addMsgDebounced = debounce($scope.addMsg, 2000, false);  $scope.logReturn = function(msg) {     console.log('logReturn called with', msg);     var promise = $scope.addMsgDebounced(msg);     promise.then(function(msg) {         console.log('Promise resolved with', msg);     }); }; 

If you call logReturn multiple times in quick succession you will see the logReturn call logged over and over but only one addMsg call logged.

like image 79
Pete BD Avatar answered Sep 28 '22 13:09

Pete BD


Angular 1.3 has debounce as standard

Worth mentioning that debounce comes built in with Angular 1.3. As you'd expect, it's implemented as a directive. You can do this:

<input ng-model='address' ng-model-options="{ debounce: 500 }" /> 

The $scope.address attribute is not updated until 500ms after the last keystroke.

If you need more control

If you want more granularity, you can set different bounce times for different events:

<input ng-model='person.address' ng-model-options="{ updateOn: 'default blur', debounce: {'default': 500, 'blur': 0} }" /> 

Here for example we have a 500ms debounce for a keystroke, and no debounce for a blur.

Documentation

Read the documentation here: https://docs.angularjs.org/api/ng/directive/ngModelOptions

like image 33
superluminary Avatar answered Sep 28 '22 14:09

superluminary