angularrxjsangular-httpclientajax-polling

Configurable polling interval with angular and rxjs


I am trying to create continuous polling using rxjs and angular. Below is an implementation of my requirement.

https://stackblitz.com/edit/angular-sq3ke5

ngOnInit() {
    const bitcoin$ = this.http.get('https://blockchain.info/ticker');


    this.polledBitcoin$ = timer(0, this.timeInterval).pipe(
        merge(this.manualRefresh),
        concatMap(_ => bitcoin$),
        map((response: {EUR: {last: number}}) => {
          console.log(new Date() +" >> " + response.EUR.last)
          return response.EUR.last;
          }),
      );
  }

However in this example, I have added polling interval and I want it to be updated based on the value entered by user. However any changes in text input is not getting reflected in polling interval. Can someone help me achieve this result?

Thanks in advance.


Solution

  • Updating the timeInterval variable will not simply update your interval Observable, you will have to kill it and start a new Observable.

    Try this approach:

    <input [ngModel]="timeInterval" (ngModelChange)="changeInterval($event)" />
    Bitcoin price: {{ dataToShow }}
    
    
    ngOnInit() {
      this.startInterval();
    }
    
    startInterval() {
      const bitcoin$ = this.http.get('https://blockchain.info/ticker');
      this.polledBitcoin$ = timer(0, this.timeInterval).pipe(
          merge(this.manualRefresh),
          concatMap(_ => bitcoin$),
          map((response: {EUR: {last: number}}) => {
            console.log(new Date() +" >> " + response.EUR.last)
            return response.EUR.last;
            }),
        );
    
        this.sub = this.polledBitcoin$.subscribe((data) => {
          this.dataToShow = data;
        });
    }
    
    changeInterval(e) {
      this.timeInterval = e;
      if (this.sub) {
        this.sub.unsubscribe();
      }
      this.startInterval();
    }
    

    https://stackblitz.com/edit/angular-4n29cm?file=app%2Fapp.component.ts

    Edit

    A more performant approach would be to wait for the input to change and then re-create the interval again. I have used a Subject for listening to the changes in the input, wait for some time so that the user has finished typing and then restart the interval.

    ngOnInit() {
      this.startInterval();
      this.inputSub = this.inputSubject.pipe(debounceTime(500)).subscribe(() => {
        console.log('restart now')
        if (this.intervalSub) {
            this.intervalSub.unsubscribe();
        }
        // you probably don't want an interval running in zero second interval
        // add more checks here if you want, for example: this.timeInterval > 200
        if (this.timeInterval) {
          this.startInterval();
        }
      })
    }
    
    startInterval() {
      const bitcoin$ = this.http.get('https://blockchain.info/ticker');
      this.polledBitcoin$ = timer(0, this.timeInterval).pipe(
          merge(this.manualRefresh),
          concatMap(_ => bitcoin$),
          map((response: {EUR: {last: number}}) => {
            console.log(new Date() +" >> " + response.EUR.last)
            return response.EUR.last;
            }),
        );
    
        this.intervalSub = this.polledBitcoin$.subscribe((data) => {
          this.dataToShow = data;
        });
    }
    
    changeInterval(e) {
      console.log("change interval called");
      this.timeInterval = e;
      this.inputSubject.next(e);
    }
    

    https://stackblitz.com/edit/angular-c355ij?file=app%2Fapp.component.ts