Atraso de mudança de ng angular

117

Eu tenho uma entrada que filtra uma lista de repetição de ng na mudança. A repetição contém muitos dados e leva alguns segundos para filtrar tudo. Eu gostaria que houvesse um atraso de 0,5 segundo antes de iniciar o processo de filtragem. Qual é a maneira correta no angular de criar esse atraso?

Entrada

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

Repetir

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

Função de Filtro

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

obrigado

MGot90
fonte
1
Basta usar um $timeoutpor 500ms. $scope.FilterByName = function () { $timeout(_filterByName , 500)
PSL
@PSL onde na função? Só quero que a pesquisa seja executada uma vez. Se eu apenas compensar, isso criará um atraso maior e fará várias pesquisas.
MGot90
Sim, em sua função. o comentário anterior tem um trecho. Você pode usar $timeout.cancel(timeoutpromise)se um tempo limite estiver em andamento e outra alteração for acionada.
PSL
1
@PSL Obrigado funciona como um encanto!
MGot90

Respostas:

273

AngularJS 1.3+

Desde o AngularJS 1.3 você pode utilizar a debouncepropriedadengModelOptions fornecidas para conseguir isso de forma muito fácil, sem usar $timeoutnada. Aqui está um exemplo:

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);
        };
    }
]);

- OU -

Verifique o violino

Antes do AngularJS 1.3

Você terá que usar $ timeout para adicionar um atraso e provavelmente com o uso de $ timeout.cancel (previoustimeout) você pode cancelar qualquer timeout anterior e executar o novo (ajuda a evitar que a filtragem seja executada várias vezes consecutivas dentro de um intervalo de tempo)

Aqui está um exemplo:

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);
    }
});
rckd
fonte
2
Observe que ng-model-optionssó foi adicionado no Angular v1.3 (e a propriedade debounce no beta.8 ). Quem ainda precisar de uma versão anterior do Angular terá que recorrer a outras soluções, como a do PSL, ou a um módulo externo como o ng-debounce .
Vincent Sels
Uma desvantagem pode ser que isso também parece atrasar validações como o padrão ng.
Johan Baaij
19

Você pode usar $timeoutpara adicionar um atraso e provavelmente com o uso de$timeout.cancel(previoustimeout) você pode cancelar qualquer tempo limite anterior e executar o novo (ajuda a evitar que a filtragem seja executada várias vezes consecutivas dentro de um intervalo de tempo)

Exemplo:-

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

PSL
fonte
8
Para o downvoter e futuros visitantes: Esta resposta foi adicionada para Angular 1.2.x , e adicionada provavelmente antes de 1.3.x ser lançado, que tem a opção debounce com ng-model-options e nunca teve a chance de revisar a resposta antes de um melhor chegou a resposta de @rckd (cerca de 3 meses depois desta).
PSL de
4
Mesmo que eu esteja usando o angular js 1.4, ainda acho a solução $ timeout útil ng-changequando não quero debounce do modelo.
SStanley
8

Eu sei que a pergunta é muito antiga. Mas ainda quero fornecer uma maneira mais rápida de conseguir isso usando o debouncing .

Portanto, o código pode ser escrito como

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

Debounce levará o número em milissegundos.

Naibedya Kar
fonte
0

ou você pode usar a diretiva 'typeahead-wait-ms = "1000"' do 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">
Vadym Kaptan
fonte