El Hombre Sin Nombre
El Hombre Sin Nombre

Reputation: 3102

Angular - Multiple subscribe sequence doesn´t work

In angular i want to create a multiple subscribe sequence. When the first subscribe is complete do next subscribe. Similar to this.

this.globalCtrl.getSon().subscribe(
                  response => {
                    this.son= response;
                  },
                  error => {
                    console.log(error);
                  },
                  () => {
                   //DOESN´T ENTER IN THIS SUBSCRIBE
                    this.dashboardCtrl.getMarkers(this.son).subscribe(

                      response => {
                        this.markers = response["body"]["data"];
                        if (this.markers.length == 0) {
                          this.toast.fire({
                            type: "error",
                            title: "No hay datos geográficos del grupo seleccionado"
                          });
                        }
                        this.timezone = response["body"]["timezone"];
                      },
                      error => {
                        console.log(error);
                      }
                    );

The problem: Doesn't enter in the second subscription and the 'response' has data. ¿Anyone know how can i do that?

UPDATE

If i put second subscription inside response like this

  this.globalCtrl.getSon().subscribe(
                      response => {
                        this.son= response;
                        this.dashboardCtrl.getMarkers(this.son).subscribe(

                          response => {
                            this.markers = response["body"]["data"];
                            if (this.markers.length == 0) {
                              this.toast.fire({
                                type: "error",
                                title: "No hay datos geográficos del grupo seleccionado"
                              });
                            }
                            this.timezone = response["body"]["timezone"];
                          },
                          error => {
                            console.log(error);
                          }
                        );

Works but view doesn´t show data. When i refresh the view data load properly, but in first load doesn´t load data.

UPDATE 2: USING SWITCH MAP

  this.globalCtrl.getfather().pipe(
      switchMap(son=> this.dashboardCtrl.getMarkers(son.toString()).subscribe( /ERROR
        response => {
          this.markers = response["body"]["data"];
          if (this.markers.length == 0) {
            this.toast.fire({
              type: "error",
              title: "No hay datos geográficos del grupo seleccionado"
            });
          }
          this.timezone = response["body"]["timezone"];
        },
        error => {
          console.log(error);
        }
      )
    );

The propierty subscribe doesn´t exist in OperatorFunction

Maybe the observable cause the error

 getFather(): Observable<any> {
    return this.grupo.asObservable();
  }

Upvotes: 0

Views: 915

Answers (4)

Dino
Dino

Reputation: 8292

Having a subscription inside a subscription is called Flattening

In response to @DeborahK answer using switchMap would work, but it would be a misuse of it. switchMap would be a way to go if your first observable could change while there's a subscription already to it. Better approach would be to use mergeMap also (previously) known as flatMap

mergeMap - Use it when you have an Observable whose results are another Observable

switchMap - Use it when you have an Observable that can change and whose results are another Observable

If your first Observable emits something, mergeMap wouldn't discard the previous Observable, therefore your inner subscription would still be subscribed to the previous one. In switchMap it would discard the previous Observable and inner subscription would subscribe to the inner one.

The solution:

import { mergeMap } from 'rxjs/internal/operators/mergeMap';
.......
.......

this.globalCtrl.getSon().pipe(
  mergeMap((response) => {
    this.son = response;
    return this.dashboardCtrl.getMarkers(this.son)
  })
).subscribe((res) => {
  this.markers = response["body"]["data"];
});

Upvotes: 1

DeborahK
DeborahK

Reputation: 60596

It is recommended that you do not nest a subscribe inside another subscribe. It makes it difficult to manage and just about impossible to correctly unsubscribe. Instead, use switchMap.

Here is an example from one of my sample apps:

  todosForUser$ = this.http.get<User>(`${this.userUrl}/${this.userName}`)
    .pipe(
      switchMap(user =>
        this.http.get<ToDo[]>(`${this.todoUrl}?userId=${user.id}`)
      )
    );

You can see this code here:

https://stackblitz.com/edit/angular-todos-deborahk

Using your code, it would be something like this (NOT syntax checked):

import { switchMap } from 'rxjs/operators';

this.globalCtrl.getSon()
 .pipe(
    switchMap(son => this.dashboardCtrl.getMarkers(son))
 ).subscribe(...);

UPDATE: Simplified initial example, which originally demonstrated how to handle multiple related datasets.

Upvotes: 2

Dino
Dino

Reputation: 8292

Your second subscription is put in a wrong place. It should be inside the response of a first subscription

this.globalCtrl.getSon().subscribe(
                  response => {
                    this.son= response;
                    // ADD THE OTHER SUBSCRIBE HERE
                  },
                  error => {
                    console.log(error);
                  }

The observable callback has 3 types - next, error, complete

You were putting the second subscription in a complete callback and that was the reason it was never called (Your first observable never completed).

Read more about Observables here

Upvotes: 1

Luis Rico
Luis Rico

Reputation: 635

You have to move your second subscription inside your first one:

this.globalCtrl.getSon().subscribe(
              response => {
                this.son= response;
                  this.dashboardCtrl.getMarkers(this.son).subscribe(
                  response => {
                    this.markers = response["body"]["data"];
                    if (this.markers.length == 0) {
                      this.toast.fire({
                        type: "error",
                        title: "No hay datos geográficos del grupo seleccionado"
                      });
                    }
                    this.timezone = response["body"]["timezone"];
                  },
                  error => {
                    console.log(error);
                  }
              },
              error => {
                console.log(error);
              } 
                );

Upvotes: 1

Related Questions