mo_maat
mo_maat

Reputation: 2240

Angular Observable Service being called multiple times

I have a service that has a method that returns and observable. I have a component that subscribes to that observable when my it is loaded. I have a console.log in my service to log every time it is called. When I run my app and look at my console window, I see 3 instances of my logged value. Why is that? I'm only subscribing to the observable service once.

I actually have a broader question than this simple example where I noticed that when I have several subscriptions to my service, I get even more repeated calls to my functions and the service. Why does that happen given that my assumption is that the purpose of using rxjs and subjects is to have some basic form of state management and the purpose of that being to avoid retrieving data that hasn't changed.

Service:

export class ResultService {

  protected id;
  private results$ = new Subject<any>();
  
  constructor(
    private dataService: DataService, 
  ) { }

  getResults(id): Observable<any> {
    console.log('get result called in ResultService');
    this.dataService.getResults(id)
      .subscribe(res => {
        console.log('the value of res in ResultService constructor');
        this.results$.next(res);
      })
    return this.results$.asObservable();
  }
}

Result Component

private subscription$;
@Input() id;

  constructor(
       this.subscription$ = this.resultService.getResults(this.competitionId);
       this.fetchResults(this.competitionId);
  ) { }

  ngOnInit() {
    this.fetchResults(this.id);
  }
  fetchResults(id){
    this.resultService.getResults(this.id)
      .subscribe((data) => 
      {
        data.forEach(resultElement => {
           //do something
        });
        this.resultList = data;
      })
  }
  ngOnChanges() {
    this.fetchResults(this.id);
  }

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

Summary Page html file - has the result component as a child that it passes id

  <ion-col size-lg="5">
    <ion-row>
      <ion-col>
        <app-results-component [id]="id"></app-results-component>
      </ion-col>
    </ion-row>
  </ion-col>

Summary Page ts file

  private id: number;
  private dataSub$;
  private resultData : any;

  ngOnInit() {
    this.activatedRoute.params.subscribe(params => {
      this.competitionId = params['id'];
      this.getData(this.id);
    }
  }

  getData(id) {
    this.dataSub$ = this.resultService.getResults(id);
    this.dataSub$
    .subscribe((data) => {
        this.resultData = data;
        this.dosomething(this.resultData);
      })
  }

  ngOnDestroy() {
    this.dataSub$.unsubscribe(); //unsubscribe
  }

Upvotes: 2

Views: 5036

Answers (2)

huan feng
huan feng

Reputation: 8633

  • You need to add if condition if (changes.id)

  • It seems there's no need to call it in onInit

  • You need to unSubscribe the observable

     private unSub = new Subject();
    
     constructor(
         private resultService: ResultService
     ) { }
    
     fetchResults(id){
         this.resultService.getResults(this.id)
             .pipe(
                 takeUntil(this.unSub)
             )
             .subscribe((data) =>
             {
                 data.forEach(resultElement => {
                     //do something
                 });
                 this.resultList = data;
             })
     }
     ngOnChanges(changes: SimpleChanges) {
         if (changes.id) {
             this.fetchResults(this.id);
         }
     }
    
     ngOnDestroy(): void {
         this.unSub.next();
         this.unSub.complete();
     }
    

Upvotes: 0

Nafeo Alam
Nafeo Alam

Reputation: 4692

You have to unsubscribe your subscription.

Sample code:

constructor(
    private resultService: ResultService
  ) { }

  subscription$ //declare

  ngOnInit() {
    this.fetchResults(this.id);
  }

  fetchResults(id){
    this.subscription$ = this.resultService.getResults(this.id)
      .subscribe((data) => 
      {
        data.forEach(resultElement => {
           //do something
        });
        this.resultList = data;
      })
  }

  ngOnChanges() {
    this.fetchResults(this.id);
  }

  ngOnDestroy() {
    this.subscription$.unsubscribe() //unsubscribe
  }
}

Upvotes: 1

Related Questions