da1lbi3
da1lbi3

Reputation: 4519

Get data from 2 observables inside resolver

I have a few services that are working with the observable principle. I want to get the results of 2 services inside a resolver to use at my page. But the result inside the page is just a empty data object. I have also tried first() instead of take(1), but no difference there.

My resolver:

@Injectable({
  providedIn: 'root'
})
export class CompanyResolver implements Resolve<any> {
  constructor(private companyResolver: CompanyService, private countryService: CountryService, private genderService: GenderService) { }


  resolve(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ) {

    return forkJoin({
      countries: this.countryService.getCountries().pipe(take(1)),
      genders: this.genderService.getGenders().pipe(take(1)),
    });
  }
}

My page:

export class SettingsCompanyOverviewComponent implements OnInit {

  constructor(
    public countryService: CountryService,
    private route: ActivatedRoute
  ) {
    console.log(this.route.snapshot);
  }

  ngOnInit(): void {
  } 
}

Service:

export class CountryService {

  private countryObserver$: BehaviorSubject<CountryInterface[]> = new BehaviorSubject([]);

  constructor(
    private apiService: ApiService
  ) {
    this.getData();
  }

  getCountries(): Observable<GenderInterface[]> {
    return this.countryObserver$.asObservable();
  }

  private getData(): void {
    this.apiService.get<CountryInterface[]>(ApiRoutes.getCountries, null).then(res => {
      this.countryObserver$.next(res);
    });
  }
}

I don't get what is going wrong as I really expect data from both services.

Edit: It seems that the first data from the observable is empty, after that I get the expected results. I thought that BehaviorSubject gives the last result back?

Upvotes: 1

Views: 87

Answers (1)

AVJT82
AVJT82

Reputation: 73357

As established in comment, BehaviorSubject emits the initial value in the resolver, because it takes some time for the http-request to complete, but by then, when new value would be emitted, the resolver has already done its job.

Looks to me that you wouldn't need the behaviorSubject as a middleman? You could assign it directly to an observable. If you need to share same data, you can use shareReplay which just emits the value without making a http request. So something like this for the country service:

export class CountryService {

  constructor(
    private apiService: ApiService
  ) { }

  countries$ = this.getData().pipe(shareReplay());

  private getData(): Observable<CountryInterface[]> {
    return this.apiService.get<CountryInterface[]>(ApiRoutes.getCountries, null)
  }
}

Then in your resolver, just listen to countries$ instead of your BehaviorSubject.

return forkJoin({
  countries: this.countryService.countries$.pipe(take(1)),
  //....
});

You can apply the same for your other service like I did above for the country service.

Upvotes: 1

Related Questions