Is it acceptable to nest an observable subscription within another observable subscription

1.3k views Asked by At

I'm struggling to get my head around observables in Angular2. I have a 2 subscriptions to an observable within an observeable forEach.

So it's as follows:

  1. forEach gets the route ID (poll id)
  2. (Nested in 1) subscribe gets the poll from the database using the route ID (poll id)
  3. (Nested in 2) subscribe gets the createdBy user from the database using the poll ids createdById

As you can see there's a lot of nesting going on which just doesn't feel right. Is there a better way for me to achieve this?

This is my code:

poll: Poll;
createdBy: string;

constructor(public route: ActivatedRoute, public teamPollsService: TeamPollsService) { }

ngOnInit(): void {
let id: any;

// 1. 
this.route.params.forEach((params: Params) => {
  id = params['id'];

  // 2.
  this.pollService.getPoll(id).subscribe((x) => {
      this.poll = x;

      // 3.
      this.users.getDbUser(x.createdById).subscribe((user) => {
        createdBy = `${user.firstName} ${user.lastName}`;
      });
    });
});

Thanks.

2

There are 2 answers

1
Yaroslav Admin On BEST ANSWER

Use flatMap() instead:

this.route.params
    .flatMap((params: Params) => {
        id = params['id'];
        return this.pollService.getPoll(id);
    })
    .flatMap((x) => {
        this.poll = x;
        return this.users.getDbUser(x.createdById);
    })
    .subscribe((user) => {
        createdBy = `${user.firstName} ${user.lastName}`;
    });

It will automatically unwrap nested observables and will help to avoid problem similar to callback hell.

0
Asti On

This might not be a good fit for Rx. This is because you have side effects in all subscriptions, and it isn't good practice to execute side-effects in flatMap or switchMap because you will not be able to predict the number of times they will execute when other operators are involved - ideally, they should be pure functions.

I can see that you're using Typescript, and you should possibly use async/await to avoid all those callbacks.