Search code examples
javascriptfirebaseionic-frameworkfirebase-realtime-databaseangularfire2

Calling then function after fetching data from firebase in ionic 3


I want fetch data from firebase after that I want to execute another function. Second function have to wait until first one is complete .

this.oAngularFireDatabase.database.ref('Users').orderByKey()
            .on('value', snapshot => {
              if (snapshot.hasChildren()) {
                snapshot.forEach(innerSnap => {
                  if (innerSnap.hasChild(user.uid)) {
                    //User role key
                    this.loggedInUserUserRoleKey = innerSnap.key;
                    //User id
                    this.loggedInUserId = user.uid;

                    //User name
                    this.loggedInUserName = innerSnap.child(user.uid).child("user_name").val();

                    if (innerSnap.child(user.uid).hasChild("user_image")) {
                      //User Image
                      this.loggedInUserImage = innerSnap.child(user.uid).child("user_image").val();
                    }
                    return false;
                  }
                })
              }
            }) 

I can't call then function after on it gives me an error. In my above code, I want call another function after all data are fetch from firebase.


Solution

  • The Firebase on() method can fire multiple times: once when it initially loads the data, and again whenever the data changes. Since a promise (the thing you call then() on) can only resolve once, on() can't return a promise.

    There are two options here:

    1. You want to only load the data once.

      If this is the case, you should use Firebase's once() method, which does return a promise.

      this.oAngularFireDatabase.database.ref('Users').orderByKey()
          .once('value').then(snapshot => {
            if (snapshot.hasChildren()) {
              snapshot.forEach(innerSnap => {
                if (innerSnap.hasChild(user.uid)) {
                  //User role key
                  this.loggedInUserUserRoleKey = innerSnap.key;
                  //User id
                  this.loggedInUserId = user.uid;
      
                  //User name
                  this.loggedInUserName = innerSnap.child(user.uid).child("user_name").val();
      
                  if (innerSnap.child(user.uid).hasChild("user_image")) {
                    //User Image
                    this.loggedInUserImage = innerSnap.child(user.uid).child("user_image").val();
                  }
                  return false;
                }
              })
            }
          }).then(value => {
              // TODO: perform subsequent action on boolean value
          })
      
    2. You want to listen for changes on the data too.

      If this is the case, you should put the subsequent action you want to take into the on() callback:

      this.oAngularFireDatabase.database.ref('Users').orderByKey()
          .on('value', snapshot => {
            if (snapshot.hasChildren()) {
              snapshot.forEach(innerSnap => {
                if (innerSnap.hasChild(user.uid)) {
                  //User role key
                  this.loggedInUserUserRoleKey = innerSnap.key;
                  //User id
                  this.loggedInUserId = user.uid;
      
                  //User name
                  this.loggedInUserName = innerSnap.child(user.uid).child("user_name").val();
      
                  if (innerSnap.child(user.uid).hasChild("user_image")) {
                    //User Image
                    this.loggedInUserImage = innerSnap.child(user.uid).child("user_image").val();
                  }
                }
              })
              // TODO: perform subsequent action on data
            }
          }) 
      

    Note that both of these operations look pretty expensive for what they're trying to accomplish: scanning a JSON tree for a specific value is an anti-pattern in Firebase, and typically means you should modify/augment your JSON to allow a direct lookup or query.

    For example, I suspect you now have a structure like /Users/$randomkey/$uid: { ..user data... }. For better performance, consider storing the user data directly under their UID: /Users/$uid: { ..user data... }. This removes the need for a query, and allows you to directly load the data for a user from this.oAngularFireDatabase.database.ref('Users').child(user.uid).