How to make an http call every 2 minutes with RXJS?
Asked Answered
A

6

33

I have a service that will make a call to my rest service every 2 minutes. On my service I have the following function

  getNotifications(token: string) {
     const body = 'xxxxxxxxx=' + token;
     return this.http.post('/rest/ssss/ddddddd/notificationcount', body, this.options)
          .map((res) => res.json());
  }

On my component I call my service function to call the API.

this.notificationService.getNotifications(this.token).subscribe((data) => {
  console.log(data);
});

I want to make this call every 2 minutes, what is the best way to do this?

Alurd answered 28/6, 2017 at 17:37 Comment(1)
Did you look at repeatWhen?Mantissa
Y
79

Since you are already using Observables, simply make full use of it :) Obersvable.interval() is your good friend here:

In your component, do this:

Observable
    .interval(2*60*1000)
    .timeInterval()
    .mergeMap(() => this.notificationService.getNotifications(this.token))
    .subscribe(data => {
        console.log(data);
    });

Explanation:

  1. .interval() creates an observable that emits an event every 2 minutes.
  2. .timeInterval() convert an Observable that emits items into one that emits indications of the amount of time elapsed between those emissions.
  3. .mergeMap() then wraps your each and every of service call, transform the results into an observable and return it. This ensure that the your service call at 0th, 2nd, 4th, 6th....minute is called synchronously. (think of there is a lot of .then()), i.e, service at 2nd minute will only be called on after the 0th minute's call, and 4th will only after 2nd, and so on.
  4. .subscribe() finally you can subscribe to the data

Update:

If you are using pipeable operators (rxjs5 and above), simply pipe the operators instead of chaining them:

interval(2 * 60 * 1000)
    .pipe(
        mergeMap(() => this.notificationService.getNotifications(this.token))
    )
    .subscribe(data => console.log(data))
Ypsilanti answered 28/6, 2017 at 17:57 Comment(4)
I've had a similar case with the one described in this question. What I need to know since I am newbie to Angular is whether this data can be rendered dynamically to page. Let's say that this data is an array of objects and I iterate through them on a table, would this table be updated with the 'new' data returned by the service every 2 minutes?Ation
@Ation yes. it will, as long as you bind the data correctlyYpsilanti
@Ation you can do that by using the async pipe in Angular 5Maier
@Maier yes this is another approach. This way, data does not need to be an array of objects but the observable itself, so the above code needs to be modified.Ation
G
14

If you are using rxJs 6+, you can simlpy use interval method to do. like this -

import { interval } from 'rxjs';

interval(3000).subscribe(x => /* do something */)
Georgettegeorgi answered 27/9, 2019 at 10:23 Comment(0)
V
2

If you don't want to make an http call and simply want to do something after 2 minutes, then you can do something like below.

 Observable.interval(2*60*1000)
  .subscribe(() => {
    // do something.
    // or callSomeMethod();
  });

if you are using rxjs 6+ then you can do like this :

  interval(2*60*1000)
  .subscribe(() => {
    // do something.
    // or callSomeMethod();
  });

There is one more important thing you would like to do, You shoud destroy this observable once you leave your current page, because you don't want the extra computation going on behind the scene when these are not actually needed.

There are multiple options to unsubscribe from this observable.

  1. You should save the reference to the observable and unsubscribe from it in onDestroy method.

     this.observableRef = Observable.interval(60000)
     .subscribe(() => {
       // do something
      });
    
     // call this method in OnDestroy method of the page.
     this.observableRef.unsubscribe();
    
  2. OR use ngx-take-until-destroy

     Observable.interval(60000)
     .takeUntil(this.destroyed$)
     .subscribe(() => {
       //  do something
     });
    
Ventriloquism answered 29/5, 2018 at 19:7 Comment(0)
L
0

I had a similar need.can be useful to someone and hence writing it here.My Angular version is 9.1.5. I am checking if the user is logged in and sending a http request every 10 minutes until the user is in that component.

 const secondsCounter = interval(60000); //Refreshes every 10 minutes
 secondsCounter
 .pipe(
   tap(console.log),
   takeWhile(x => this.notificationService.isLoggedIn()),
   flatMap(() => this.notificationService.getNotifications(this.token))
 ).subscribe()
Lange answered 21/7, 2020 at 11:15 Comment(0)
L
0

Small my example with limit of execution time and manual stop by result

this.insalesXlsSubject.pipe(
  switchMap((job_id: string) => {
    return interval(1000).pipe(
      mergeMap((i) => {
        return this.http.get(`${environment.backend}/${this.route.snapshot.params.insales_app_name}/api/make_insales_xls?job_id=${job_id}`)
      }),
      tap((y: any) => {
        if (y.status == 'finished') {
          this.insalesXlsStatusSubject.next()
        }
      }),
      takeUntil(race([
        this.insalesXlsStatusSubject,
        timer(60 * 1000).pipe(
          takeUntil(
            this.insalesXlsStatusSubject
          )
        )
      ]))
    )
  })
).subscribe()
Liger answered 22/12, 2020 at 15:26 Comment(0)
L
-1
import {Observable} from 'rxjs/Rx';

  Observable.interval(2 * 60 * 1000).subscribe(x => {
    callyourmethod();
  });

Update After comment

this.interval = setInterval(() => {
        this.yourservicecallmethod();
    }, 2 * 60 * 1000);
Leucite answered 28/6, 2017 at 17:48 Comment(1)
Presumably he wants an observable which emits a new HTTP response every two minutes.Mantissa

© 2022 - 2024 — McMap. All rights reserved.