Prashant Gujar
Prashant Gujar

Reputation: 21

How to combine two observables to create new observable?

I have two services named 'PatientsService' and 'AppointmentService'. In third service 'AppointedPatientsService', I want to subscribe to AppointmentService to get all booked appointments with patientId and after that I want to repeatedly subscribe to PatientsService.getPatient(patientId) to get Patient's data with patientId. And then, I want to return new array named allAppointedPatients which holds all appointments with patient's data. I tried this...

 getAppointments() {
let allAppointments: Appointment[] = [];
const allAppointedPatients: AppointedPatient[] = [];

return this.appointmentService.fetchAllAppointments().pipe(
  take(1),
  tap(appointments => {
  allAppointments = appointments;

  for (const appointment of allAppointments) {
    this.patientsService.getPatient(appointment.patientId).pipe(
      tap(patient => {
        const newAppointment = new AppointedPatient(patient.firstName,
                                                  patient.lastName,
                                                  patient.address,
                                                  patient.casePaperNumber,

 appointment.appointmentDateTime);
        allAppointedPatients.push(newAppointment);
      })
    ).subscribe();
  }
  return allAppointedPatients;
}),
pipe(tap((data) => {
  return this.allAppointedPatients;
}))
);

}

This is not working and I know there must be better way to handle such scenario. Please help...

Upvotes: 1

Views: 826

Answers (2)

Andrew Radulescu
Andrew Radulescu

Reputation: 1899

You are messing up the async code (observables) with sync code by trying to return the allAppointedPatients array synchronously.

Understand first how async code is working in Javascript and also why Observables (streams) are so useful.

Try the code below and make sure you understand. Of course, I was not able to test it so make your own changes if needed.

getAppointments(): Observable<AppointedPatient[]> {
    return this.appointmentService.fetchAllAppointments()
        .pipe(
            switchMap(appointments => {

                const pacientAppointments = [];

                for (const appointment of allAppointments) {

                    // Extract the data aggregation outside or create custom operator
                    const pacientApp$ = this.patientsService.getPatient(appointment.patientId)
                        .pipe(
                            switchMap((pacient) => of(
                                new AppointedPatient(
                                    patient.firstName,
                                    patient.lastName,
                                    patient.address,
                                    patient.casePaperNumber,
                                    appointment.appointmentDateTime
                                )
                            ))
                        )

                    pacientAppoinments.push(pacientApp$);
                }

                return forkJoin(pacientAppointments);
        });
}

Upvotes: 2

Mohammad Niazmand
Mohammad Niazmand

Reputation: 1547

You can use forkJoin:

forkJoin(
            getSingleValueObservable(),
            getDelayedValueObservable()
            // getMultiValueObservable(), forkJoin on works for observables that complete
          ).pipe(
            map(([first, second]) => {
              // forkJoin returns an array of values, here we map those values to an object
              return { first, second };
            })
          );

Upvotes: 1

Related Questions