chink
chink

Reputation: 1643

Stop a continuous function being called once I leave the component in Angular

I am building an app using Angular. As part of it, I am making an API call every 1 min for continuous data. My code looks like.

ngOnInit() {
    this.getRealTimeData();
  }

  intervalId : any

  getRealTimeData() {
    this.getChillerApiData()
    clearInterval(this.intervalId);
    this.intervalId = setInterval(() => {
      this.getChillerApiData();
    }, 1000);
  }

  getChillerApiData() {
    this.api.getFirstChillerData()
      .subscribe((first_data:any) => {
        this.first_api_data = first_data;
        console.log(this.first_api_data)
        this.putPrimaryPumpData();
      });
  }

I am getting data every 1 min or whatever time interval I mention. But what is happening is when I leave the component and go on to another component, still I see API calls made regularly at specified interval (I can see the console logs). How do I stop that from happening? I mean once I leave this component API calls should also stop.

Upvotes: 1

Views: 2798

Answers (4)

Barremian
Barremian

Reputation: 31105

Use OnDestroy() lifecycle hook.

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

export class AppComponent implements OnInit, OnDestroy {
  private intervalId: any
  private chillerDataSubscription: Subscription;

  constructor() { }

  ngOnInit() {
    this.getRealTimeData();
  }

  getRealTimeData() {
    this.getChillerApiData()
    clearInterval(this.intervalId);
    this.intervalId = setInterval(() => {
      this.getChillerApiData();
    }, 1000);
  }

  getChillerApiData() {
    if (this.chillerDataSubscription) {
      this.chillerDataSubscription.unsubscribe();
    }
    this.chillerDataSubscription = this.api.getFirstChillerData()
      .subscribe((first_data:any) => {
        this.first_api_data = first_data;
        console.log(this.first_api_data)
        this.putPrimaryPumpData();
      });
  }

  ngOnDestroy() {
    if (this.intervalId) {
      clearInterval(this.intervalId);
    }
    if (this.chillerDataSubscription) {
      this.chillerDataSubscription.unsubscribe();
    }
  }
}

See here for more details on lifecycle hooks.

I assume you are making a HTTP request inside your api service. In that case, notice the chillerDataSubscription inside the getChillerApiData() function. It makes sure any outstanding requests are unsubscribed before making a new request. It prevents accumulation of too many requests.

Upvotes: 1

Kurt Hamilton
Kurt Hamilton

Reputation: 13515

You can clear up your component in ngOnDestroy. This function is called by Angular when the component removed from the DOM.

You could clear the interval in ngOnDestroy, but in your case you're probably better off performing the interval in RxJS, which your existing call can be part of.

// other imports here
import { interval } from 'rxjs';
import { takeUntil, switchMap } from 'rxjs/operators';

// @Component decorator here
export class MyComponent implements OnInit, OnDestroy {

  // TODO: add constructor

  private destroyed: Subject<void> = new Subject<void>();

  ngOnInit() {
    // create an rxjs interval every 1000ms
    // or you could use timer(0, 1000) to start immediately
    interval(1000).pipe(
      // stop the interval whenever this.destroyed is called
      takeUntil(this.destroyed),
      // now make the api request
      switchMap(() => this.api.getFirstChillerData())
    ).subscribe(data => {
      this.first_api_data = data;
      this.putPrimaryPumpData();
    });
  }

  ngOnDestroy() {
    // called when the component is removed from the DOM. 
    // cancel the interval and tidy up
    this.destroyed.next();
    this.destroyed.complete();
  }
}

Upvotes: 1

Shai Aharoni
Shai Aharoni

Reputation: 1957

Exactly for cases like this angular provides the OnDestroy life cycle event. You can hook to this event the clear the interval.

like this:

intervalId : any

ngOnDestory() {
 clearInterval(this.intervalId);
}

Upvotes: 1

Swoox
Swoox

Reputation: 3740

First of all there are so many things wrong here.

You call an subscribition and it's not unsubscribed. You want to unsubscribe the subscribition and you want to clear the interval. If the subscribition is not cleared it will keep getting info and keep repeating it. So putPrimaryPumpData will be called everytime the subscription is fired. Which can conclude in multiple running at the same time.

Do something like:

let sub = this.api.getFirstChillerData()
  .subscribe((first_data:any) => {
    sub.unsubscribe();
    this.first_api_data = first_data;
    console.log(this.first_api_data)
    this.putPrimaryPumpData();
  });

Now this will not create like 100 of 1000 of loops. Second you can use ngOnDestroy like:

ngOnDestroy() {
  clearInterval(this.intervalId);
}

Upvotes: 1

Related Questions