¿Cómo devuelvo la respuesta de una llamada Observable/http/async en angular?
Tengo un servicio que devuelve un observable que realiza una solicitud http a mi servidor y obtiene los datos. Quiero usar estos datos pero siempre termino obteniendo undefined
. ¿Cuál es el problema?
Servicio :
@Injectable()
export class EventService {
constructor(private http: Http) { }
getEventList(): Observable<any>{
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.get("http://localhost:9999/events/get", options)
.map((res)=> res.json())
.catch((err)=> err)
}
}
Componente:
@Component({...})
export class EventComponent {
myEvents: any;
constructor( private es: EventService ) { }
ngOnInit(){
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
});
console.log(this.myEvents); //This prints undefined!
}
}
Verifiqué ¿Cómo devuelvo la respuesta de una llamada asincrónica? publico pero no pude encontrar una solución
Razón:
La razón undefined
es que estás realizando una operación asincrónica. Lo que significa que llevará algún tiempo completar el getEventList
método (dependiendo principalmente de la velocidad de su red).
Así que veamos la llamada http.
this.es.getEventList()
Después de realizar ("disparar") su solicitud http, subscribe
estará esperando la respuesta. Mientras espera, JavaScript ejecutará las líneas debajo de este código y, si encuentra asignaciones/operaciones sincrónicas, las ejecutará inmediatamente.
Entonces, después de suscribirse getEventList()
y esperar la respuesta,
console.log(this.myEvents);
La línea se ejecutará inmediatamente. Y su valor es undefined
antes de que llegue la respuesta del servidor (o de lo que sea que lo haya inicializado en primer lugar).
Es similar a hacer:
ngOnInit(){
setTimeout(()=>{
this.myEvents = response;
}, 5000);
console.log(this.myEvents); //This prints undefined!
}
**Solución:** > Entonces, ¿cómo superamos este problema? Usaremos la función de devolución de llamada que es el método "suscribir". Porque cuando los datos lleguen del servidor estarán dentro de la "suscripción" con la respuesta.
Entonces cambiando el código a:
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents); //<-- not undefined anymore
});
imprimirá la respuesta... después de un tiempo.
**Qué debes hacer:**
Es posible que haya muchas cosas que hacer con su respuesta además de simplemente registrarla; debes hacer todas estas operaciones dentro de la devolución de llamada (dentro de la subscribe
función), cuando lleguen los datos.
Otra cosa a mencionar es que si tienes antecedentes Promise
, la then
devolución de llamada se corresponde subscribe
con observables.
**Lo que no debes hacer:**
No debería intentar cambiar una operación asíncrona a una operación de sincronización (no es que pueda hacerlo). Una de las razones por las que tenemos operaciones asíncronas es para no hacer que el usuario espere a que se complete una operación mientras puede hacer otras cosas en ese período de tiempo. Supongamos que una de sus operaciones asíncronas tarda 3 minutos en completarse; si no tuviéramos las operaciones asíncronas, la interfaz se congelaría durante 3 minutos.
Lectura sugerida:
El crédito original de esta respuesta es para: ¿ Cómo devuelvo la respuesta de una llamada asincrónica?
Pero con el lanzamiento de angular2 conocimos el mecanografiado y los observables, por lo que se espera que esta respuesta cubra los conceptos básicos del manejo de una solicitud asincrónica con observables.
Realizar una llamada http en angular/javascript es una operación asincrónica. Entonces, cuando realice una llamada http, asignará un nuevo hilo para finalizar esta llamada y comenzar la ejecución de la siguiente línea con otro hilo. Es por eso que obtienes un valor indefinido. así que haga el siguiente cambio para resolver esto
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents); //<-this become synchronous now
});
Puedes usar asyncPipe si usas myEvents solo en la plantilla.
Aquí ejemplo con asyncPipe y Angular4 HttpClient ejemplo
Los observables son vagos, por lo que debes suscribirte para obtener el valor. Lo suscribiste correctamente en tu código pero simultáneamente registraste el resultado fuera del bloque 'suscribir'. Por eso es "indefinido".
ngOnInit() {
this.es.getEventList()
.subscribe((response) => {
this.myEvents = response;
});
console.log(this.myEvents); //Outside the subscribe block 'Undefined'
}
Entonces, si lo registra dentro del bloque de suscripción, registrará la respuesta correctamente.
ngOnInit(){
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents); //Inside the subscribe block 'http response'
});
}
Aquí el problema es que estás inicializando this.myEvents
en subscribe()
un bloque asíncrono mientras estás console.log()
fuera del subscribe()
bloque. Entonces console.log()
, recibir una llamada antes de this.myEvents
que se inicialice.
Mueva su código console.log() también dentro de subscribe() y listo.
ngOnInit(){
this.es.getEventList()
.subscribe((response)=>{
this.myEvents = response;
console.log(this.myEvents);
});
}