1

I need to be able to loop an array of objects, check a certain property of the object and if it's true, make a HTTP request to get extra data for the object.

Currently, I have written it as I logically thought about it in my head:

public refreshParticipants(housingTransactionId: string): Observable<Array<Participant>> {
    const url: string = `${config.apiBaseUrl}`;

    this.authHttpService.get(url)
        .subscribe(response => {
            let participants = response.json().map(p => Participant.createFromResponse(p));

            participants.forEach(participant => {
                if (participant.isBusinessUser) {
                    this.getParticipantBranchFromHousingTransaction(participant.id, housingTransactionId)
                        .subscribe((branch) => {
                            participant.branchId = branch.id;
                        })
                }
                this.participants.push(participant);
            });

            return Observable.of(this.participants);
        });

My problem is that the requests aren't being waited for, therefore this.participants isn't getting populated.

I'm not sure how to write it so that this.participants is populated with both participants who have needed the extra data from the HTTP request and the participants who didn't.

1
  • after set branchId, you can push it to partipants? Commented Jul 24, 2018 at 9:45

3 Answers 3

3

A neater way to achieve what you're trying to do is to use a single observable to resolve the whole set of data:

this.authHttpService.get(url).pipe(
    flatMap((response) => {
        let participants = response.json().map(p => participant.createFromResponse(p));             
        let partDataRequests: Observable<Participant>[] = [];
        participants.forEach((participant) => {
            if (participant.isBusinessUser) {
                partDataRequests.push(this.getParticipantBranchFromHousingTransaction(participant.id, housingTransactionId).map((branch) => { participant.branchId = branch.id; return participant; });
            } else {
                partDataRequests.push(of(participant));
            }
        });
        return forkJoin(partDataRequests);
    })
).subscribe((enrichedParticipants) => {
    this.participants = enrichedParticipants;
});

(This is assuming rxjs v6, if using rxjs v5, the syntax may be slightly different but the principles would be the same)

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you so much, Mark. This is exactly what I was after even if my question didn't explain it very well. I'm using rxjs v5 but was able to get it to work!
Great, glad to hear it @Chris. I find that with observables, boiling it down to "how do I make a single observable that represents the whole flow I want" is a good principle to follow.
1

The issue is, that your participant is beeing pushed before the subscription has a response. Just move the push line into your subscription. Like

    participants.forEach(participant => {
         if (participant.isBusinessUser) {
             this.getParticipantBranchFromHousingTransaction(participant.id, housingTransactionId)
               .subscribe((branch) => {
                  participant.branchId = branch.id;
                  this.participants.push(participant);
               });
          } else {
            this.participants.push(participant);
          }
    });

2 Comments

This way, I would not get participants who are not "business users". I need all participants but if they are "business users", I need the extra data.
Updated my answer.
0

Is this what you are looking for?

    this.authHttpService.get(url)
        .subscribe(response => {
            let participants = response.json().map(p => Participant.createFromResponse(p));

            participants.forEach(participant => {
                if (participant.isBusinessUser) {
                    // perform a request for extra data
                    this.getParticipantBranchFromHousingTransaction(participant.id, housingTransactionId)
                        .subscribe((branch) => {
                            participant.branchId = branch.id;
                            this.participants.push(participant);
                        })
                }
                else {
                    // this participant does not require extra data
                    this.participants.push(participant);
                }
            });
        })

Notice that the array will be finalized, not when the foreach loop ends, but when all of the requests get responses.

1 Comment

Sorry, I forgot to mention that this is inside a method. Please see my updated question - the method returns before the data is populated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.