I am using Angular 6 and I need to extend an array of contacts that I get from a Http request. Each contact has a userId. And I need to loop through the contacts array, making another request based on the userId so I can extend each contact with user's first name and last name. I have to mention that I have to do it before subscribe.
contacts.service.ts
findContacts(params: paramsModel): Observable<resultsModel> {
const httpParams = this.getParams(params);
return this.http.get<resultsModel>('/getAllContacts', {
params: httpParams
}).pipe(
map((res: any) => {
// here I get all the contacts but I need to loop through each contact and make another request based on the userId to get info about the user that belongs to each contact
// res looks like this:
// {
// [
// id: 1,
// name: test1,
// userId: 14
// ],
// [
// id: 2,
// name: test2,
// userId: 9
// ],
// ..
// }
// and I need to extend it to like this:
// {
// [
// id: 1,
// name: test1,
// userId: 14,
// userFirstName: John,
// userLastName: Doe,
// ],
// [
// id: 2,
// name: test2,
// userId: 9,
// userFirstName: Jane,
// userLastName: Doe,
// ],
// ..
// }
// I tried a lot of approaches, but with no luck.. (including flatMap, switchMap, working with chaining observables, but I didn't find an example with looping before subscribe that I could reproduce so I got lost quickly).
// this is one of them:
// res.map(contact => {
// this.http.get<any>('getUserById?userId=' + contact.userId).pipe(
// map( user => {
// // using underscore for extend
// _.extend(contact, {
// userFirstName: user.firstName,
// userLastName: user.lastName
// });
// return contact;
// })
// );
// });
return someFunction(res, params);
})
);
}
contacts.data.ts
export class ContactsData extends Data {
constructor(private contactsService: ContactsService) {
super();
}
loadContacts(
params: paramsModel
) {
this.loadingSubject.next(true);
this.contactsService.findContacts(params).pipe(
tap(res => {
this.entitySubject.next(res.items);
this.paginatorTotalSubject.next(res.totalCount);
}),
catchError(err => of(new resultsModel([], err))),
finalize(() => this.loadingSubject.next(false))
).subscribe();
}
}
contacts-list.component.ts
export class ContactsListComponent implements OnInit {
contactsData: ContactsData;
ngOnInit() {
const params = new paramsModel();
this.contactsData.loadContacts(params);
}
}
Solution with the help of Michał Tkaczyk:
contacts.service.ts
findContacts(params: paramsModel): Observable<resultsModel> {
const httpParams = this.getParams(params);
return this.http.get<resultsModel>('/getAllContacts', {
params: httpParams
}).pipe(
map((res: any) => res),
switchMap(res => {
const requests = res.map(contact => {
return this.http.get<any>('getUserById?userId=' + contact.userId).pipe(
map(userData => {
console.log(userData);
return _.extend(contact, {
userFirstName: user.firstName,
userLastName: user.lastName
});
})
);
});
return forkJoin(requests);
}),
map( res => {
return someFunction(res, params);
})
);
}