1

I am developing a web application and maintaining the data in Firebase in the following way.

enter image description here

There can be several nodes under the "Users" node and in each of those nodes, I am storing users information such as name, gender etc.

Now I am trying to retrieve names of all users using the following Javascript function.

function getList(){
    var nameList = new Array();
    var uidList = new Array();
    var query = firebase.database().ref('Users');

    query.once("value").then(function(snapshot) {
        snapshot.forEach(function(childSnapshot) {
            var name = childSnapshot.val().Name;
            var uid = childSnapshot.key;
            alert(name);  //first alert
            nameList.push(name);
            uidList.push(uid);
        });
    });

    var len = nameList.length;
    alert(len); //second alert
}

When I run this on my browser, at first it shows the length of the array is 0 (in the second alert) and then it shows the name which is being retrieved from the database (in the first alert).

Why is the second alert executing before the first alert? What is the appropriate way to retrieve data from Firebase, so that I can detect that data is retrieved and then execute further code to get the length of namelist array?

I have tried using a while loop while "name" and "uid" are null, but that didn't work.

Himanshu
  • 12,071
  • 7
  • 46
  • 61
Sadman Rizwan
  • 189
  • 1
  • 2
  • 14
  • 2
    Possible duplicate of [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) –  Mar 16 '18 at 08:35
  • I tried answers of that question, but that didn't help me. That's why I posted this one. @ChrisG – Sadman Rizwan Mar 16 '18 at 08:48
  • 1
    You should have mentioned this, because your question gives *zero* indication that you are aware of asynchronousness. It reads exactly like the dozens of other questions per month that are about the exact same issue. –  Mar 16 '18 at 09:38

3 Answers3

1

Try this:

function getList() {
  var query = firebase.database().ref('Users');

  query.once("value").then(snapshots => snapshots.map(snapshot => ({
    name: snapshot.val().Name,
    uid: snapshot.key
  }))).then(result => {
    console.log(result);
  });
}

The queried array is remapped to an array of { name: "name", uid: "key" } objects.

0

You are trying to populate an array from a callback function, the callback function happens sometime in the future. So you are alerting before the callback executes

I suggest you use promises or async

adot
  • 398
  • 1
  • 3
  • 14
  • Cen you please give me an example of how I should use promises or async in my function given above? I am new in Javascript, so I am a little bit confused about these two terms. – Sadman Rizwan Mar 16 '18 at 08:56
  • 1
    If you are new to javascript, you should definitely choose one of those concepts and read up. – adot Mar 16 '18 at 09:05
0

Promises are the way to handle such situations. Use promises for asynchronous call to handle the execution of result after the function for pushing the data into firebase completes that way the alert will show the length of namelist.

function getList(){
    var nameList = new Array();
    var uidList = new Array();
    var query = firebase.database().ref('Users');

    let getData = new Promise((resolve, reject) => {
            query.once("value").then(function(snapshot) {
                snapshot.forEach(function(childSnapshot) {
                    var name = childSnapshot.val().Name;
                    var uid = childSnapshot.key;
                    alert(name);  //first alert
                    nameList.push(name);
                    uidList.push(uid);
                });
                resolve(nameList)
            })
        });

    getData.then((nameList) => {
        alert(nameList.length)
    })
}
Himanshu
  • 12,071
  • 7
  • 46
  • 61
  • It is resulting in error, saying "getData.then is not a function". – Sadman Rizwan Mar 16 '18 at 09:16
  • 1
    Move `resolve(nameList)` one `});` further down and it could work. –  Mar 16 '18 at 09:39
  • 1
    `alert(len(nameList))` => `alert(nameList.length)` –  Mar 16 '18 at 10:30
  • Also note that query is already a Promise, which means doing this is enough: https://pastebin.com/vLbndxgz OP marked this as best because he's mad at me. Edit: this, in fact: https://pastebin.com/5Jn2S7fU –  Mar 16 '18 at 10:31
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/166954/discussion-between-himanshu-and-chris-g). – Himanshu Mar 16 '18 at 11:52