Como criar temporizador no angular2

95

Preciso de um cronômetro no Angular 2, que marque após um intervalo de tempo e faça alguma tarefa (pode ser chamada de algumas funções).

Como fazer isso com o Angular 2?

kuntal
fonte
2
Inclua código apenas o suficiente para permitir que outros reproduzam o problema. Para obter ajuda com isso, leia Como criar um exemplo mínimo, completo e verificável. Se for possível criar um exemplo ao vivo do problema para o qual você pode criar um link (por exemplo, em sqlfiddle.com ou jsbin.com ), faça-o - mas também inclua o código em sua própria pergunta. Nem todos podem acessar sites externos e os links podem quebrar com o tempo.
Prasad
15
Na verdade, esta é uma pergunta muito útil. Os observáveis ​​são importantes para aprender e usar. Mesmo que o usuário não tenha o código para ir, esta questão será útil para outros.
Winnemucca,
Este comentário cai no mesmo balde, mas nenhuma das 2 pessoas anteriores ajudou, apenas comentou sobre a questão ... Aparentemente, as pessoas estão usando setTimeout novamente agora.
rbnzdave 01 de
setTimeout é realmente old-school - confira o novo TimerObservable abaixo
Philip
2
deixe this._timer = setInterval (() => this.getWidgetData (), 10000); e certifique-se de chamar clearInterval (this._timer); em destruir
crh225

Respostas:

129

Além de todas as respostas anteriores, eu faria isso usando RxJS Observables

verifique Observable.timer

Aqui está um código de amostra, começará após 2 segundos e, em seguida, avança a cada segundo:

import {Component} from 'angular2/core';
import {Observable} from 'rxjs/Rx';

@Component({
    selector: 'my-app',
    template: 'Ticks (every second) : {{ticks}}'
})
export class AppComponent {
  ticks =0;
  ngOnInit(){
    let timer = Observable.timer(2000,1000);
    timer.subscribe(t=>this.ticks = t);
  }
}

E aqui está um êmbolo de trabalho

Atualizar Se quiser chamar uma função declarada na classe AppComponent, você pode fazer o seguinte:

** Supondo que a função que você deseja chamar seja chamada de func ,

ngOnInit(){
    let timer = Observable.timer(2000,1000);
    timer.subscribe(this.func);
}

O problema com a abordagem acima é que se você chamar 'this' dentro de func, ele se referirá ao objeto assinante em vez do objeto AppComponent, que provavelmente não é o que você deseja.

No entanto, na abordagem a seguir, você cria uma expressão lambda e chama a função func dentro dela. Dessa forma, a chamada para func ainda está dentro do escopo do AppComponent. Esta é a melhor forma de o fazer na minha opinião.

ngOnInit(){
    let timer = Observable.timer(2000,1000);
    timer.subscribe(t=> {
        this.func(t);
    });
}

verifique este plunker para código de trabalho.

Abdulrahman Alsoghayer
fonte
Devo conseguir passar uma função para `timer.subscribe (t => this.ticks = t);` que é chamada a cada tick?
kuntal
@matrixwebtech Sim, o 't => this.ticks = t' é uma expressão lambda, exatamente o mesmo que 'function (t) {this.ticks = t}'
Abdulrahman Alsoghayer
Eu tento timer.subscribe (function name () {console.log ("hhhhhh")}); que funciona, mas como eu chamo uma função que declarou separadamente ngOnInit () {let timer = Observable.timer (2000,1000); timer.subscribe (function () {this.fun ();}); } fun () {console.log ("hhhhhh")}
kuntal
@matrixwebtech verifique minha resposta atualizada para exemplos.
Abdulrahman Alsoghayer
1
@Notflip Sob o capô, timerparece usar setInterval(). Mas, você pode passar o animationFrameplanejador (que usa requestAnimationFrame()) para usá-lo em vez do asyncplanejador padrão . Tudo que você precisa fazer é Observable.timer(*,*,Scheduler.animationFrame), dado import {Scheduler} from ‘rxjs’.Embora, timernele não pareça funcionar. Ainda parece usar setInterVal(). No entanto, em outros tipos de observáveis, como Observable.range(0,1000,Scheduler.animationFrame), o requestAnimationFrameé usado com certeza. Em termos de desempenho, não posso responder com certeza agora.
Abdulrahman Alsoghayer
79

Outra solução é usar TimerObservable

TimerObservable é uma subclasse de Observable.

import {Component, OnInit, OnDestroy} from '@angular/core';
import {Subscription} from "rxjs";
import {TimerObservable} from "rxjs/observable/TimerObservable";

@Component({
  selector: 'app-component',
  template: '{{tick}}',
})
export class Component implements OnInit, OnDestroy {

  private tick: string;
  private subscription: Subscription;

  constructor() {
  }

  ngOnInit() {
    let timer = TimerObservable.create(2000, 1000);
    this.subscription = timer.subscribe(t => {
      this.tick = t;
    });
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }
}

PS: Não se esqueça de cancelar a assinatura.

Philip
fonte
3
a parte de cancelar é fundamental
Tucker
como você cancela a inscrição? e quando?
Miguel Stevens de
1
@Notflip ngOnDestroy é chamado durante a desinicialização do componente: this.subscription.unsubscribe();cancela a inscrição.
Philip
Como você pode usar this.subscription sem referenciá-lo acima?
Winnemucca
2
Como você pausa e reinicia?
Dani
11
import {Component, View, OnInit, OnDestroy} from "angular2/core";

import { Observable, Subscription } from 'rxjs/Rx';

@Component({

})
export class NewContactComponent implements OnInit, OnDestroy {

    ticks = 0;
    private timer;
    // Subscription object
    private sub: Subscription;


    ngOnInit() {
        this.timer = Observable.timer(2000,5000);
        // subscribing to a observable returns a subscription object
        this.sub = this.timer.subscribe(t => this.tickerFunc(t));
    }
    tickerFunc(tick){
        console.log(this);
        this.ticks = tick
    }

    ngOnDestroy(){
        console.log("Destroy timer");
        // unsubscribe here
        this.sub.unsubscribe();

    }


}
Unnikrishnan Parameswaran
fonte
3
Isso não adiciona nada que já não tenha sido explicado em outras respostas, ou adiciona?
Günter Zöchbauer
5

Com rxjs 6.2.2 e Angular 6.1.7, eu estava recebendo um:

Observable.timer is not a function

erro. Isso foi resolvido substituindo Observable.timerpor timer:

import { timer, Subscription } from 'rxjs';

private myTimerSub: Subscription;    

ngOnInit(){    
    const ti = timer(2000,1000);    
    this.myTimerSub = ti.subscribe(t => {    
        console.log("Tick");    
    });    
}    

ngOnDestroy() {    
    this.myTimerSub.unsubscribe();    
}
Matt Saunders
fonte
3
Para fazer o cancelamento da assinatura, você deve ter uma variável de assinatura como @ alexis-poo acima. Consulte: stackoverflow.com/questions/40181169/… . Baseio-o na sua resposta que não funciona como está escrito a esse respeito.
Reid,
Eu amo esse cara que está sempre atualizando os Posts para as versões mais recentes do Angular ... Sempre lutamos tanto com o AngularJS e o Angular. Obrigado cara!
chainstair
4

Você pode simplesmente usar o utilitário setInterval e usar a função de seta como retorno de chamada para que thisaponte para a instância do componente.

Por ex:

this.interval = setInterval( () => { 
    // call your functions like 
    this.getList();
    this.updateInfo();
});

Dentro de seu gancho de ciclo de vida ngOnDestroy, limpe o intervalo.

ngOnDestroy(){
    clearInterval(this.interval);
}
Shivang Gupta
fonte
3

Enfrentei um problema que tive que usar um timer, mas tive que exibi-los em 2 componentes ao mesmo tempo, mesma tela. Criei o timerObservable em um serviço. Assinei o cronômetro em ambos os componentes, e o que aconteceu? Não será sincronizado, porque uma nova assinatura sempre cria seu próprio fluxo.

O que eu gostaria de dizer, é que se você planeja usar um timer em vários lugares, coloque sempre .publishReplay(1).refCount() no final do Observer, pois ele publicará o mesmo stream fora dele todas as vezes.

Exemplo:

this.startDateTimer = Observable.combineLatest(this.timer, this.startDate$, (localTimer, startDate) => {
  return this.calculateTime(startDate);
}).publishReplay(1).refCount();
xyztdanid4
fonte
você pode compartilhar sua implementação?
Nitish Kumar de
1

Encontrou um pacote npm que facilita isso com RxJS como um serviço.

https://www.npmjs.com/package/ng2-simple-timer

Você pode 'assinar' um cronômetro existente para não criar um bazilhão de cronômetros se estiver usando-o muitas vezes no mesmo componente.

Simon_Weaver
fonte
1

Se você deseja executar um método no ngOnInit, pode fazer algo assim:

importe estas 2 bibliotecas de RXJS:

import {Observable} from 'rxjs/Rx';
import {Subscription} from "rxjs";

Em seguida, declare o temporizador e a assinatura privada, por exemplo:

timer= Observable.timer(1000,1000); // 1 second for 2 seconds (2000,1000) etc
private subscription: Subscription;

Por último, mas não menos importante, execute o método quando o cronômetro parar

ngOnInit() {
  this.subscription = this.timer.subscribe(ticks=> {
    this.populatecombobox();  //example calling a method that populates a combobox
    this.subscription.unsubscribe();  //you need to unsubscribe or it will run infinite times
  });
}

Isso é tudo, Angular 5

Alexis Poo
fonte
0
Set Timer and auto call service after certain time
// Initialize from ngInit
ngOnInit(): void {this.getNotifications();}

getNotifications() {
    setInterval(() => {this.getNewNotifications();
    }, 60000);  // 60000 milliseconds interval 
}
getNewNotifications() {
    this.notifyService.getNewNotifications().subscribe(
        data => { // call back },
        error => { },
    );
}
Nazmul Nadim
fonte