javascript - Ionic 3 - Actualizar Observable con Datos Asíncronos
Para una aplicación de redes sociales, tengo una colección de objetos de feed referenciados por sus IDs usando AngularFire 2. Una vez que cada uno de estos IDs tiene sus datos relevantes extraídos de la base de datos que almacena los objetos de feed reales, deseo actualizar el objeto Observable feedCards con esta información para poder mostrar asincrónicamente una colección de objetos de feed en mi HTML. Es una cadena de eventos bastante confusa, así que permíteme resumírtelo.
Enfoque paso a paso
displayFeed()se invoca justo antes de que elNavControllercargue el componentefeeden la páginaMain.displayFeed()obtiene el elementotwiner, que es esencialmente un elemento de perfil de usuario, y luego almacena el perfil de usuario en la variableuserProfile.- Una vez que se carga el perfil del usuario, el Observable global
feedCardsse establece igual aloadFeed(), que devuelve un array Observable. loadFeed()utiliza el valoriddel objeto globaluserProfilepara cargar la lista de referencias del feed almacenadas en el perfil del usuario.- Luego se suscribe a esta instantánea y la variable local
feedse establece igual a la lista de resultados de referencias de feed. loadFeeddevuelve un objeto Observable en el cual la lista de referenciasfeedse mapea según los datos que contiene cada referencia de feed.pullFeedData(number)recibe una referencia a un objeto feed y devuelve un observable con los datos asociados del feed.
Lo que funciona
alert(JSON.stringify(feedData));muestra una alerta con el objetofeedcorrectoBásicamente todo lo demás.
Lo que no funciona
- El
feed.map(...no actualiza el array feed porquepullFeedData(number)obtiene y devuelve elfeedDatade forma asincrónica. Por lo tanto,alert(JSON.stringify(data));endisplayFeed()muestra una alerta con[null].
Código
feed.ts userProfile:any;
feed: FirebaseListObservable<any>;
feedData: FirebaseObjectObservable<any>;
feedCards: Observable<any[]>;
constructor(public db: AngularFireDatabase, public nativeStorage: NativeStorage) {}
displayFeed():void {
this.nativeStorage.getItem('twiner').then((res) => {
this.userProfile = res;
this.feedCards = this.loadFeed();
this.feedCards.subscribe((data)=>{
alert(JSON.stringify(data));
})
});
}
loadFeed():Observable<any[]> {
var feed;
this.feed = this.db.list('/twiners/' + this.userProfile.id + '/feed', { preserveSnapshot: true });
this.feed.subscribe((snapshots)=>{feed = snapshots});
return Observable.of(feed.map((snapshot) => {
this.pullFeedData(snapshot.val()).subscribe((feedData)=>{
alert(JSON.stringify(feedData));
return feedData;
});
})).delay(1000);
}
pullFeedData(twine:number):any {
return this.db.object('/twines/' + twine, { preserveSnapshot: true });
}
feed.html<ion-content fullscreen scroll="true" overflow-scroll="true">
<ion-card *ngIf="feedCards | async">feedCards exist</ion-card>
<twine-feed-card *ngFor="let feedCard of feedCards | async"
[data]="feedCard"
></twine-feed-card>
</ion-content>
Resumen
feed.map no actualiza feed con los objetos feed porque los nuevos datos se están obteniendo de forma asincrónica. Necesito una solución para esto.
¡Gracias!
Respuesta #1
Un observable suscrito no devuelve un valor. Devuelve un objeto Subscription que puedes usar para cancelar la suscripción más tarde.
Puedes usar switchMap para cambiar del primer observable al siguiente durante la llamada y devolver los valores. También puedes usar forkJoin, que llamará a un arreglo de observables y esperará hasta que se devuelva el arreglo de valores en la suscripción. Primero declara la variable de clase feed como un Observable.
feed: Observable<any>;
Entonces en tu loadFeed():Observable<any[]>
return this.feed.switchMap((snapshots) => {
let observableArray = [];
snapshots.forEach(snapshot =>{
observableArray.push(this.pullFeedData(snapshot.val()));
});
return Observable.forkJoin(observableArray)
})
