124

I have an input which filters a ng-repeat list on change. The repeat contains a lot of data and takes a few seconds to filter through everything. I would like their to be 0.5 second delay before I start the filtering process. What is the correct way in angular to create this delay?

Input

 <input ng-model="xyz" ng-change="FilterByName()" />

Repeat

 <div ng-repeat"foo in bar">
      <p>{{foo.bar}}</p>
 </div>

Filter Function

 $scope.FilterByName = function () {
      //Filtering Stuff Here
 });

Thanks

5
  • 1
    Just use a $timeout for 500ms. $scope.FilterByName = function () { $timeout(_filterByName , 500) Commented Oct 19, 2014 at 2:30
  • @PSL where in the function? I only want the search to execute once. If I just offset it, it will just create a bigger delay and do multiple searches. Commented Oct 19, 2014 at 2:31
  • Yeah, in your function. prev comment has a snippet. You can use $timeout.cancel(timeoutpromise) if one timeout is in progress and another change gets triggered. Commented Oct 19, 2014 at 2:32
  • 1
    plnkr.co/edit/CSsr3r?p=preview Commented Oct 19, 2014 at 2:40
  • ng-model-options='{ debounce: 1000 }' Commented Jul 21, 2017 at 17:20

4 Answers 4

291

AngularJS 1.3+

Since AngularJS 1.3 you can utilize the debounce property ngModelOptions provides to achieve that very easy without using $timeout at all. Here's an example:

HTML:

<div ng-app='app' ng-controller='Ctrl'>
    <input type='text' placeholder='Type a name..'
        ng-model='vm.name'
        ng-model-options='{ debounce: 1000 }'
        ng-change='vm.greet()'
    />

    <p ng-bind='vm.greeting'></p>
</div>

JS:

angular.module('app', [])
.controller('Ctrl', [
    '$scope',
    '$log',
    function($scope, $log){
        var vm = $scope.vm = {};

        vm.name = '';
        vm.greeting = '';
        vm.greet = function greet(){
            vm.greeting = vm.name ? 'Hey, ' + vm.name + '!' : '';
            $log.info(vm.greeting);
        };
    }
]);

-- OR --

Check the Fiddle

Before AngularJS 1.3

You'll have to use $timeout to add a delay and probably with the use of $timeout.cancel(previoustimeout) you can cancel any previous timeout and run the new one(helps to prevent the filtering to be executed multiple times consecutovely within a time interval)

Here is an example:

app.controller('MainCtrl', function($scope, $timeout) {
    var _timeout;

    //...
    //...

    $scope.FilterByName = function() {
        if(_timeout) { // if there is already a timeout in process cancel it
            $timeout.cancel(_timeout);
        }
        _timeout = $timeout(function() {
            console.log('filtering');
            _timeout = null;
        }, 500);
    }
});
Sign up to request clarification or add additional context in comments.

2 Comments

Note that ng-model-options was only added in Angular v1.3 (and the debounce property in beta.8). Those who still need to use an older version of Angular will have to resort to other solutions, like the one from PSL, or by using an external module like ng-debounce.
A downside could be that this seems to delay validations like ng-pattern as well.
22

You could use $timeout to add a delay and probably with the use of $timeout.cancel(previoustimeout) you can cancel any previous timeout and run the new one(helps to prevent the filtering to be executed multiple times consecutovely within a time interval)

Example:-

app.controller('MainCtrl', function($scope, $timeout) {
  var _timeout;

 //...
 //...

  $scope.FilterByName = function () {
    if(_timeout){ //if there is already a timeout in process cancel it
      $timeout.cancel(_timeout);
    }
    _timeout = $timeout(function(){
      console.log('filtering');
      _timeout = null;
    },500);
  }
 });

Plnkr

2 Comments

To the downvoter and future visitors: This answer was added for Angular 1.2.x, and added probably before 1.3.x was released which has the the debounce option with ng-model-options and never got a chance to revise the answer before a better answer from @rckd came in (around 3 months after this one).
Even though I am using angular js 1.4 I still find the $timeout solution useful with ng-change when I don't want to debounce the model.
9

I know the question is too old. But still want to provide one quicker way to achieve this using debouncing.

So the code can be written as

<input ng-model="xyz" ng-change="FilterByName()" ng-model-options="{debounce: 500}"/>

Debounce will take the number in milliseconds.

Comments

1

or you can use directive ' typeahead-wait-ms="1000" ' from angular-ui

<input 
   typeahead="name for name in filterWasChanged()"
   typeahead-wait-ms="1000"
   type="text" placeholder="search"
   class="form-control" style="text-align: right" 
   ng-model="templates.model.filters.name">

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.