Ben
Ben

Reputation: 4120

Chain observables to load dependent datas

I'm loading an employee in my resolver. This employee returns a list of town's ids. I want to load all the towns from this town's id list in the same resolver. But I don't want to return the list of town, I want to return the employee. The loaded town will be added in a cache service to be used later. Here is my code

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {

    return this.employeeService.getEmployee(route.params['id'])
        .pipe(
            map(employee => {
                const townsObservables = [];
                employee['town_list'].forEach((townId) => {
                    townsObservables.push(this.townService.getTown(townId));
                });
                return forkJoin(townsObservables).pipe(
                    map(town => {
                        this.townCache.addTown(town);
                        return employee;
                    })
                );
            })
        );
}

Problem: the forkJoin is never executed and the route snapshot data in my component return an Observalbe instead of a employee.

route.snapshot.data['employee'] // returns Observable {_isScalar: false, source: Observable, operator: MapOperator}

The employeeService is working well without all the code in pipe, this code works like expected (I can get my employee in my snapshot data):

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
    return this.employeeService.getEmployee(route.params['id']);
}

Question: what is the correct way to load related datas without returning them in a resolver? I was about to try to use two separates resolvers but the resolvers cannot be chained (there is no way to tell resolver B to use datas from resolver A).

I'm using Angular 6 with RXJS ^6.2.1.

Upvotes: 2

Views: 900

Answers (1)

m1ch4ls
m1ch4ls

Reputation: 3435

You should use mergeMap if you want to subscribe forkJoin.

return this.employeeService.getEmployee(route.params['id'])
    .pipe(
        mergeMap(employee => { // <-- HERE changed to mergeMap
            const townsObservables = [];
            employee['town_list'].forEach((townId) => {
                townsObservables.push(this.townService.getTown(townId));
            });
            return forkJoin(townsObservables).pipe(
                map(town => {
                    this.townCache.addTown(town);
                    return employee;
                })
            );
        })
    );

Main difference between map and mergeMap:

map(val => of(val)) -> results in Observable<Observable<val>>

mergeMap(val => of(val)) -> results in Observable<val>

It is equivalent to .pipe(map(val => of(val)), mergeAll())

Upvotes: 1

Related Questions