values recorrer objetos matriz llenar elementos ejemplos array agregar javascript angular firebase callback firebase-database

javascript - recorrer - Firebase no recibe datos antes de que se cargue la vista: matriz vacía devuelta antes de completar



llenar array javascript (4)

En el siguiente código, guardo la clave de cada elemento y una dirección de correo electrónico en una tabla, y para recuperar el objeto a recuperar de la tabla original usando dicha clave. Puedo ver que los elementos se colocan en la matriz rawList cuando console.log, pero la función devuelve this.cartList antes de que this.cartList algo, por lo que la vista no recibe ninguno de los datos. ¿Cómo puedo hacer para que this.cartList espere que this.cartList rawList antes de que se devuelva?

ionViewWillEnter() { var user = firebase.auth().currentUser; this.cartData.getCart().on(''value'', snapshot => { let rawList = []; snapshot.forEach(snap => { if (user.email == snap.val().email) { var desiredItem = this.goodsData.findGoodById(snap.val().key); desiredItem.once("value") .then(function(snapshot2) { rawList.push(snapshot2); }); return false } }); console.log(rawList); this.cartList = rawList; }); }

He intentado poner this.cartList = rawList en varias ubicaciones diferentes (antes de return false , incluso dentro de la declaración .then , pero eso no resolvió el problema.


La siguiente llamada a función es asincrónica y se está quedando fuera del alcance antes de que rawList tenga la oportunidad de actualizarse porque esta llamada a la base de datos lleva bastante tiempo:

desiredItem.once("value").then(function(snapshot2) { rawList.push(snapshot2); });

También está empujando la instantánea directamente a esta lista, cuando debería presionar snapshot2.val() para obtener el valor bruto.

Así es como arreglaría tu código:

ionViewWillEnter() { var user = firebase.auth().currentUser; this.cartData.getCart().on(''value'', snapshot => { // clear the existing `this.cartList` this.cartList = []; snapshot.forEach(snap => { if (user.email == snap.val().email) { var desiredItem = this.goodsData.findGoodById(snap.val().key); desiredItem.once("value") .then(function(snapshot2) { // push directly to the cartList this.cartList.push(snapshot2.val()); }); } return false; }); }); }


El problema es la llamada Promise (async .once () a firebase) dentro del bucle forEach (sincronización). El forEach Loop no va a esperar la instrucción then (), entonces en la siguiente iteración los datos de la iteración anterior simplemente se pierden ...

let snapshots = [1, 2, 3]; let rawList = []; snapshots.forEach((snap) => { console.log(rawList.length) fbCall = new Promise((resolve, reject) => { setTimeout(function() { resolve("Success!"); }, 2500) }); fbCall.then((result) => { rawList.push(result); }); })

Es necesario que cada uno inserte toda la promesa en RawList y luego espere a que se resuelvan y hagan lo mismo con los resultados.

var snapshots = [1, 2, 3]; var rawList = []; var counter = 0; snapshots.forEach((snap) => { console.log(rawList.length) var fbCall = new Promise((resolve, reject) => { setTimeout(function() { resolve("Success!" + counter++); }, 1500) }); rawList.push(fbCall); }) Promise.all(rawList).then((res) => { console.log(res[0]); console.log(res[1]); console.log(res[2]); });

El asunto es que todavía es un poco incómodo asignar this.cartList = Promise.all (rawList) ya que lo convierte en una Promesa. Entonces, ¿podría reconsiderar su diseño y hacer algo como un servicio getCartList? (No sé cómo es tu aplicación: p)


Como está utilizando angular, también debería usar angularfire2 , que utiliza Observables para resolver este problema. Todavía utilizarás el SDK normal para muchas cosas, pero para buscar y enlazar datos no se recomienda usar Firebase solo sin angularfire2 ya que hace que estas cosas sean menos manejables.

Lo bueno de este enfoque es que puede aprovechar cualquier método de Observable , como filter , first , map , etc.

Después de instalarlo simplemente hazlo:

public items$: FirebaseListObservable<any[]>; this.items$ = this.af.database.list(''path/to/data'');

Y en la vista:

{{items$ | async}}

Para esperar a que aparezcan los datos.


Utilice AngularFire2 y RxJS Esto le ahorrará mucho tiempo, y lo hará de la manera adecuada y fácil de mantener mediante el uso de los operadores RxJS, puede aprender sobre los operadores aquí learnrxjs