Reputation: 307
I know there are tons of questions and answers on using Javascript promises to load returned Firebase objects, but I haven't succeeded in capturing the data in an array.
The issue: I've set up an array (productArray
below) to iteratively take in values of a Firebase snapshot, but the array remains empty after exiting the forEach
loop.
database.js:
getProductList = function(){
let productArray =[];
loadFBData = function(){
firebase.initializeApp(config);
return firebase.database().ref().once("value", function(snapshot){
return snapshot.val();
});
}
Promise.all([loadFBData()]).then(function(snapshot) {
snapshot.forEach(function(product) {
productArray.push(product.val());
});
});
}
Question: I think I'm using Promise.all
wrong, but can't figure out how (also am new asynchronous functions). Thanks for any hints on how to get productArray
to successfully load.
Edit: To elaborate, it seems snapshot
is loading with the correct Firebase data, and the forEach
is correctly looping through each item in snapshot
but productArray
becomes (or remains) empty outside of the Promise.all
statement.
Update I implemented all the suggestions below and yet, the program will not stop long enough to build an array from the snapshot object. Last year I used Angularfire's $loaded
function which was so effective in getting the program to wait so I don't understand why an ordinary JS promise
won't work here. Does it make sense to resort to timeout
? I even tried to combine alexmac's and Pointy's suggestions, but no cigar:
getProductList = function(){
let productArray =[];
loadFBData = function(){
firebase.initializeApp(config);
return new Promise(resolve => {
firebase.database().ref().once('value')
.then(function(snapshot){
return resolve(function(snapshot){
productArray = Object.keys(snapshot).map((key, prod) => prod);
});
});
});
}
loadFBData();
}
Upvotes: 2
Views: 1078
Reputation: 892
I think you're missing an understanding of both promises and the Firebase SDK.
First, note that all Firebase SDK functions return promises, so there's no need to create your own. Second, Promise.all is for combining multiple promises. A single promises can be chained off of with a simple .then()
.
I have a video on saving and querying data here: Save and Query Firebase Data
I have another video on promises here: Promises
You should be initializing firebase at the very top of your page. It only needs to be initialized once, so don't initialize it within a function.
You can call firebase.initializeApp(config)
just after loading the Firebase SDK on the page. Or you can reference Firebase Hosting's init.js
as shown below.
The following example loads the Firebase SDK, uses my testing db's init.js
file to initialize firebase, then queries, manipulates and returns an array.
Note that Firebase doesn't support zero-indexed arrays, so everything you get back from Firebase will be an unsorted object. This example shows a few different ways of returning the data :)
<html>
<head>
<script src="https://www.gstatic.com/firebasejs/4.3.0/firebase.js"></script>
<script src="https://quiver-two.firebaseapp.com/__/firebase/init.js"></script>
<script>
function loadFirebaseArray(path) {
return firebase.database().ref(path).once('value').then(snap => snap.val());
}
function toArray(items) {
return Object.keys(items).reduce((array, key) => {
const value = items[key];
array.push({key, value});
return array;
}, []).sort();
}
loadFirebaseArray('stackoverflow').then(items => {
console.log('items', items);
const asArray = toArray(items);
alert(JSON.stringify(asArray));
const justTheValues = asArray.map(x => x.value).sort();
alert(justTheValues);
});
</script>
</head>
</html>
Upvotes: 1
Reputation: 19597
A working example might look like this:
getProductList = () => {
let loadFBData = () => {
firebase.initializeApp(config);
return new Promise(resolve => {
firebase.database().ref().once('value', resolve);
});
}
let productArray =[];
loadFBData()
.then(snapshot => {
productArray = Object.keys(snapshot).map((key, prod) => prod);
}
Here, I use promisification to create a promise for firebase
query. So loadFBData
returns a promise, I can create a promise chain or use ES7 async/await to wait until promise will be fulfilled to use result.
Upvotes: 0