Home > Software design >  Is this a reasonable way to queue Observables
Is this a reasonable way to queue Observables

Time:10-22

I am relatively new to rxjs and angular. I have a projectRev that I need to retrieve, then I want to retrieve its parent. The API dictates two calls...

I have read a lot of SO about queuing Observables but they are all trivial and I am getting lost converting the trivial example into something that applies to me.

Here is something that does work... Once the first observable is done, call the second one. Simple?

My question: is there a TECHNICAL reason this approach is flawed. Again... it works. At least on a dev machine that isn't stressed out....

Thanks

getItems() {
  console.log('get project rev');
  let prId = this.activatedRoute.snapshot.params.id;
  console.log(prId);

  this.projrevSvc.getItemById(prId).subscribe(
    (data) => {
      console.log('this was fetched :  '   data);
      this.myItem = data;
      this.getProj();

    });
} //getItems

getProj() {
  console.log('pr.pid '   this.myItem.ProjectId);
  this.projectSvc.getItemById(this.myItem.ProjectId).subscribe(
    (data) => {
      console.log('this project was fetched :  '   data);
      this.myProject = data[0];
      console.log('prid '   this.myItem.id)
      console.log(this.myProject);
    });
}

CodePudding user response:

Your code works. No one can deny that it will work. If the route were to fire often, you would have issues, in that if the route changed and the first call to getProj returned AFTER the second call to getProj, then you would have stale data. So, while it works, it's not fail proof.

The following uses a switchMap so that follow up calls get cancelled and we never risk having stale data.

this.projrevSvc.getItemById(prId)
  .pipe(
    switchMap(item => {
      return this.projectSvc.getItemById(item.ProjectId)
        .pipe(
          map(project => ([item, project])
        );
    })
  ).subscribe(([item, project]) => console.log(item, project))

AND THEN... you should make the stream fully reactive by consuming the params.id as an observable... see here:

this.activatedRoute.params
  .pipe(
    pluck('id'), 
    switchMap(id => this.projrevSvc.getItemById(id))
    switchMap(item => {
      return this.projectSvc.getItemById(item.ProjectId)
        .pipe(
          map(project => ([item, project])
        );
    })
  ).subscribe(([item, project]) => console.log(item, project))

Then feel good because you wrote some fully reactive code that reacts to the changes from the state in the router. Pretty rad.

CodePudding user response:

You need to check this article for more information https://blog.angular-university.io/rxjs-higher-order-mapping/

But in short answer, you can use something like that

getElements() {
  let prId = this.activatedRoute.snapshot.params.id;
  this.projrevSvc.getItemById(prId)
    .pipe(switchMap(response => this.projectSvc.getItemById(response.ProjectId)))
    .subscribe((nestedReponse) => this.myItem = nestedResponse);
}
  • Related