TypeScript using forkJoin on array of objects

Viewed 2356

Let's say I've got a web service that will return basic data as follows (result is named CustomerGroups):

{
    0: {
        Name: 'Group 1',
        Customers: {
            0: {
                CustomerNo: 1,
                Name: 'Customer 1'
            },
            1: {
                CustomerNo: 2,
                Name: 'Customer 2'
            }
        }
    },
    1: {
        Name: 'Group 2',
        Customers: {
            0: {
                CustomerNo: 3,
                Name: 'Customer 3'
            },
            1: {
                CustomerNo: 4,
                Name: 'Customer 4'
            }
        }
    }
}

Furthermore i've got a web-service that will return detailed customer data:

{
    CustomerNo: 1,
    Street: 'Test Street 123',
    PostCode: '99999',
    City: 'Blabla',
    ...
}

What I want to do is to combine the result of both services using a forkJoin in an Angular4 injectable service. But I stuck when I try to request each detailed information on a given customer:

ReadAll(useCache?: boolean): Observable<ICustomerGroup[]> {
    if (!this.customerGroupCache || !useCache) {
        return this.http.get(this.urlGetAll)
            .map((res: Response) => res.json())
            .flatMap((customerGroups: any[]) => {
                if (customerGroups.length > 0) {
                    return Observable.forkJoin(
                        customerGroups.map((customerGroup: any) => {
                            return this.customerService.get(/* any CustomerNo of customerGroup.Customers */)
                            // ^---- This is my problem!!!
                        })
                    );
                }
                // No data! Return empty array
                return Observable.of([]);
            })
            .catch((error: any) => Observable.throw(error.message || 'Server error'));
    }

    return Observable.of(this.customerGroupCache);
}

How can I use the forkJoin to loop over each CustomerGroup (flatMap used to do that) and get the detailed information for each Customer? Is it possible to use forEach inside a forkJoin?

The result of forkJoin should look like:

{
    0: {
        Name: 'Group 1',
        Customers: {
            0: {
                CustomerNo: 1,
                Name: 'Customer 1',
                Street: 'Test Street 123',
                PostCode: '99999',
                City: 'Blabla'
            },
            1: {
                CustomerNo: 2,
                Name: 'Customer 2',
                Street: 'Test Street 456',
                PostCode: '888',
                City: 'Blabla'
            }
        }
    }
    ...
}

Solution

As per description by taras-d, I missed mergeMap to combine the results of multiple Observables. My final source looks like:

ReadAll(useCache?: boolean): Observable<ICustomerGroup[]> {
    if (!this.customerGroupCache || !useCache) {
        return this.http.get(this.urlGetAll)
            .mergeMap((res: Response) => {
                const customerObservables = [];
                let groups = res.json();

                groups.forEach((group, i) => {
                    group.Customers.forEach((cust, j) => {
                        customerObservables.push(this.customerService.get(cust.CustomerNo));
                    });
                });

                return Observable.forkJoin(customerObservables)
                    .map(customers => {
                        this.customerGroupCache = this.buildCustomerGroupArray(groups, customers);
                        return this.customerGroupCache;
                    });
            });
    }

    return Observable.of(this.customerGroupCache);
}

Put it all together:

private buildCustomerGroupArray(allGroups: any, allCustomers: any): Array<ICustomerGroup> {
    let result: Array<ICustomerGroup> = Array<ICustomerGroup>();
    allGroups.forEach((group, index) => {
        let newGroup = new CustomerGroup();
        newGroup.ActionFlag = ActionType.Undefined;
        newGroup.Name = group.Name;
        newGroup.OldName = group.OldName;
        newGroup.CustomerList = Array<ICustomerGroupItem>();

        group.Customers.forEach((cust, index2) => {
            if (allCustomers.find(p => p.CustomerNo === cust.CustomerNo)) {
                let currCust = allCustomers.find(p => p.CustomerNo === cust.CustomerNo);
                let newGroupItem: ICustomerGroupItem = new CustomerGroupItem({
                    ActionFlag: ActionType.Undefined,
                    CustomerName: currCust.Name,
                    CustomerNo: currCust.CustomerNo
                });

                newGroup.CustomerList.push(newGroupItem);
            }
        });

        result.push(newGroup);
    });

    return result;
}
1 Answers
Related