http request every x seconds in angular

13,985

Solution 1

Use Observable.interval:

import {Observable} from 'rxjs/Rx';
...
constructor(...) {
  Observable.interval(30000).subscribe(x => { // will execute every 30 seconds
    this.ionViewDidLoad();
  });
}

OR inside your ionViewDidLoad function:

Observable.interval(3000)
          .timeInterval()
          .flatMap(() => this.http.request('http://mywebserver.com/apps/random.php')
          .map(res=> res.json())
          .subscribe(data=>{
              console.log(JSON.stringify(data));
              loader.dismiss();
              this.fact = data;
            });

Edit to answer your comment. From the Rxjs docs:

The timeInterval operator converts a source Observable into an Observable that emits indications of the amount of time lapsed between consecutive emissions of the source Observable. The first emission from this new Observable indicates the amount of time lapsed between the time when the observer subscribed to the Observable and the time when the source Observable emitted its first item. There is no corresponding emission marking the amount of time lapsed between the last emission of the source Observable and the subsequent call to onCompleted.

timeInterval by default operates on the timeout Scheduler, but also has a variant that allows you to specify the Scheduler by passing it in as a parameter.

Basically in this case it would be the reactive/Rxjs way of JavaScript´s native setInterval() function.

Solution 2

I would create a separate service to make your http requests:

@Injectable()
export class RandomService {
  constructor(http: HttpClient) { }

  getRandom() {
    return this.http.get('http://mywebserver.com/apps/random.php');
  }
}

Now you could simply call randomService.getRandom() inside of setInterval, but you can also use observable operations (there is an Observable.interval for example) to handle this for you in ionViewDidLoad:

async function ionViewDidLoad() {
  let loader = this.LoadingController.create({
    content: 'Please Wait',
  });
  await loader.present();

  // x number of seconds
  this.interval$ = interval(x).pipe(
    // make first request right away; otherwise we have to wait x seconds before first one
    startWith(),

    // cancel previous request if it had not finished yet
    switchMap(() =>
      // catch the error inside to allow for a retry each time
      // you could also use `.catch` on the entire observable stream which will
      // cancel it if there's an error.
      this.randomService.getRandom().catch(err => {
        console.error(err);
        this.alertCtrl
          .create({
            title: 'Error!',
            subTitle: 'Please check your Internet Connectivity',
            buttons: ['OK'],
          })
          .present();
      }),
    ),
  );

  this.interval$.subscribe(data => this.fact = data);

  // Separate observable to dismiss loader on first emission
  this.interval$.pipe(first()).subscribe(() => loader.dismiss());
}

ionViewWillUnload() {
  this.interval$.unsubscribe();
}

NOTE: this is assuming use of RxJS 5.5 and Angular with HttpClient. You may not have these, but you can still do something very similar. You just wouldn't be able to pipe with lettable operators and if you're not using HttpClient you still have to do .map(data => data.json()) which I would do in the service.

Finally, avoid storing and manually unsubscribing if you can, as in this.interval$. Instead You might do something like this.fact$ = interval(x)... Then in your template you can do *ngFor="let fact of (fact$ | async)" and you don't have to unsubscribe manually.

Share:
13,985
user6579134
Author by

user6579134

Updated on June 15, 2022

Comments

  • user6579134
    user6579134 almost 2 years

    I'm trying to refresh an http call every x seconds in angular2.

      ionViewDidLoad() {
    
        let loader = this.LoadingController.create({
          'content':'Please Wait'
        });
        loader.present().then(()=>{
          this.http.request('http://mywebserver.com/apps/random.php').map(res=> res.json()).subscribe(data=>{
            console.log(JSON.stringify(data));
            loader.dismiss();
            this.fact = data;
          },err=>{
            loader.dismiss();
            let alert = this.alertCtrl.create({
              title: 'Error!',
              subTitle: 'Please check your Internet Connectivity',
              buttons: ['OK']
            });
          alert.present();
        })
        })
    
      }
    

    I get data when the page newly loads. But now my issue is refreshing the http call to get new data every x seconds

  • Explosion Pills
    Explosion Pills over 6 years
    What does the timeInterval do?
  • Pierre
    Pierre almost 5 years
    This is perfect solution when your http is in a service called by another service for processing etc. Thanks!
  • Wei-jye
    Wei-jye over 4 years
    As of Oct 2019 rxjs 6, startWith() will not trigger the call right away. We need to use startWith(0)