Angular ng-change delay
Asked Answered
C

4

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

Croaker answered 19/10, 2014 at 2:29 Comment(5)
Just use a $timeout for 500ms. $scope.FilterByName = function () { $timeout(_filterByName , 500)Britannia
@Britannia 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.Croaker
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.Britannia
plnkr.co/edit/CSsr3r?p=previewBritannia
ng-model-options='{ debounce: 1000 }'Arvid
S
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);
    }
});
Serriform answered 15/1, 2015 at 8:43 Comment(2)
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.Zama
A downside could be that this seems to delay validations like ng-pattern as well.Venditti
B
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

Britannia answered 19/10, 2014 at 2:54 Comment(2)
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).Britannia
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.Saidee
M
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.

Menhir answered 17/8, 2016 at 15:51 Comment(0)
I
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">
Indraft answered 1/11, 2016 at 15:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.