Home > Mobile >  Nest observables RXJS
Nest observables RXJS

Time:11-25

I have two interfaces:

interface Project {
...
CurrentProjectPhase : number
...
}

and

interface Phase {
PhaseId : number
Projects$ : Observable<Project[]>
...
}

both are returned from individual http services as oberservables.

I'm trying to sort the projects via their currentPhase attribute into the phases. Before I did this via subscribing to both and attaching a filtered subset of all project elements to the phase:

this.phaseService.loadAllPhases().subscribe((ph) => {
      this.projectService.loadAllProjects().subscribe((pj) => {
        ph.forEach((p : Phase) => {
          p.Projects = pj.filter(project => project.CurrentProjectPhase === p.Id);
        });
        this.phases = ph;
        this.projects = pj;
      })
    })

In that case the Phase had a Projects: Project[] instead of the Observable.

I would like to refactor this to stay as observables as long as possible. I've tried this:

this.projects$ = this.projectService.getProjects();

    this.phases$ = this.phaseService.getPhases().pipe(
      tap(phases => phases.map(phase=> 
        phase.Projects$ = this.projects$?.pipe(
          map(projects=> projects.filter(project => project.CurrentProjectPhase == phase.Id)))
      ))
    )

But (ofcourse) it doesn't work. Any suggestions?

CodePudding user response:

You could combine them:

const filtered = this.projectService.getProjects().pipe(
    combineLatestWith(this.phaseService.getPhases()),
    map(([projects, phases]) => {
        phases.forEach((phase) => {
            phase.projects = projects.filter(project => project.CurrentProjectPhase == phase.Id)
        });
        return phases;
    }),
)

Or something like that. My brain's a bit tired, so this might be a tad off.

Now you can subscribe to filtered to get the results whenever you need them.

CodePudding user response:

I would try to use a forkJoin if you are using HTTP calls that will both complete once it is returned. I am not sure why you would like to keep Projects as an observable in the Phases interface but maybe the code below will work:

const projects$ = this.projectService.getProjects();
const phases$ = this.phaseService.getPhases();
const combined$: Observable<Phase[]> = forkJoin([projects$, phases$]).pipe(
  map(([projects, phases]) => {
    return phases.map(phase => {
      const phaseProjects = projects.filter(project => project.CurrentProjectPhase === phase.PhaseId);
      return {...phase, Projects$: of(phaseProjects)};
    })
  })
);
  • Related