Búsqueda de sitios web

typescript - Cómo devolver un valor dentro de subscribe en Angular 4


Soy nuevo en los observables en Angular. Tengo un problema donde quiero devolver un valor dentro de un método subscribe. Tengo el siguiente método (getFirebaseData(idForm:string):observable <any[]>):

getTotalQuestions(idForm:string){
let totalQuestions:number;
this.getFirebaseData(idForm+"/Metadatos")
.subscribe(items => 
  {
    items.map(item => {
      totalQuestions=item.Total;
      console.log(totalQuestions);
    });
  }
);
console.log(totalQuestions);
return totalQuestions;
}

el primer console.log(totalQuestions) imprime 4 pero el segundo console.log(totalQuestions) imprime undefined. Entiendo que subscribe es una operación asíncrona y por esa razón el segundo console.log(totalQuestions) ("Para poder escribir el código") imprime undefined, pero no puedo encontrar la manera de devolver la variable después de que el método subscribe se haya completado. Ahora, si cambio el subscribe por map:

getTotalQuestions(idForm:string){
let totalQuestions:number;
this.getFirebaseData(idForm+"/Metadatos")
.subscribe(items => 
  {
    items.map(item => {
      totalQuestions=item.Total;
      console.log(totalQuestions);
    });
  }
);
console.log(totalQuestions);
return totalQuestions;
}

el primer console.log(totalQuestions) no imprime nada y el segundo console.log(totalQuestions) imprime undefined. Es algo que no entiendo por qué sucede.

Espero que puedas ayudarme a aclarar el concepto que no entiendo. ¡Gracias!

Respuesta #1

No puedes devolver directamente totalQuestions así, necesitas usar un sujeto para lograr eso.

getTotalQuestions(idForm:string): Observable<string> {
let totalQuestions:number;
var subject = new Subject<string>();
this.getFirebaseData(idForm+"/Metadatos")
.subscribe(items => {
    items.map(item => {

      totalQuestions=item.Total;
      console.log(totalQuestions);
      subject.next(totalQuestions);
    });
  }
);
  return subject.asObservable();
}

Uso: getTotalQuestion(idForm).subscribe((r)=>console.log(r))

Respuesta #2

Para resolver esto crearía una propiedad totalQuestions$ observable

En el archivo TS

totalQuestions$ = this.getFirebaseData(idForm + "/Metadatos").pipe(
  map(items => items.reduce((prev, {Total}) => prev + Total), 0)))
)

Y ahora en tu plantilla puedes usar el pipe async

<span>{{ totalQuestions$ | async }}</span>

Si quieres usar la variable en tu archivo TS, entonces puedes usar operadores de combinación como forkJoin o combineLatest para acceder a este valor

newVariable$ = combineLatest([totalQuestions$, ...]).pipe(
  map(([totalQuestions, ... ]) => {
    // Perform an operation here and return a value
  })
)

Artículos relacionados