rk01
rk01

Reputation: 27

Subscribe Subject only after getting data from forkJoin

I want to pass some data from one module to another module. For that I am using Subject. I have created below subject :

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class SelectedClusterService {

  constructor() { }

  public selectedClusterName = new Subject<string>();

}

I am passing some data from "oneComponent" through above service like this and redirect to "anotherComponent":

this.selectedClusterService.selectedClusterName.next(cluster_name);

And fetching data to "anotherComponent" like this:

this.selectedClusterService.selectedClusterName.subscribe(res => {
  this.selectedCluster = res;
  console.log("this.selectedCluster", this.selectedCluster);
});

This is working fine, I am getting data to "anotherComponent". But In "anotherComponent" I am using forkJoin. I want to get data from subject only after getting data from forkJoin. I am trying like this:

   ngOnInit() {
    forkJoin([
      this.dataService.getUpgradeAppList(),
      this.dataService.getClusterList()
    ]).subscribe((data: any) => {
      console.log("forkJoin :: ngOnInit ::", data);
      this.appList = data[0].apps;
      this.clusterList = data[1];

    }); 
    this.selectedClusterService.selectedClusterName.subscribe(res => {
      this.selectedCluster = res;
      console.log("this.selectedCluster", this.selectedCluster);
    });
  }

I have tried ngAfterViewInit, ngAfterContentChecked with changeDetection also I try to use setTimeout, but nothing works. Always I am getting subject data first and then forkJoin data. How I can get forkJoin first and then subject data? Any help is appreciated...

Upvotes: 2

Views: 79

Answers (1)

Dmitry S.
Dmitry S.

Reputation: 1676

First of all, there's no way to guarantee a sequence of getting data in your component as you work with async entities. I would use BehaviorSubject instead Subject to guarantee that you receive data from other component.

Your service will be like:

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class SelectedClusterService {

  constructor() { }

  public readonly selectedClusterName = new BehaviorSubject<string | undefined>(undefined);

}

Your component:

ngOnInit() {
    forkJoin([
      this.dataService.getUpgradeAppList(),
      this.dataService.getClusterList()
    ]).
    pipe(
      tap((data: any) => {
        console.log("forkJoin :: ngOnInit ::", data);
        this.appList = data[0].apps;
        this.clusterList = data[1];
      }),
      switchMap(() => this.selectedClusterService.selectedClusterName),
      filter(res => res !== undefined)
    ).subscribe(res => {
      this.selectedCluster = res;
      console.log("this.selectedCluster", this.selectedCluster);
    });     
  }

In your anotherComponent you can use the switchMap operator to start receiving data from oneComponent and the filter to ignore initial value in BehaviorSubject that we set to undefined.

Upvotes: 2

Related Questions