Variable from firebase database isn't seen globally despite outer declaration. (javascript)

I have been doing research for the past few hours on local and global variables. What I found from this question "How do I change the value of a global variable inside of a function", and a few others was that if the variable was stated before the function (outside of it) then when you want to update the variable in a function you just say the "variable = blank" without "var" proceeding it.

If you look at the function below I have three alerts, all alerting the username of the currently logged in user via firebase. The first alert, inside the firebase reference, displays the username no problem. The other two alert "undefined". I need to be able to reference the variable in all three locations, is there something I did wrong? or is there another way to do this that works and is maybe more efficient?

var database = firebase.database();
var username;

function initApp() {
  // Listen for auth state changes.
  // [START authstatelistener]
  firebase.auth().onAuthStateChanged(function(user) {
    if (user) {
      // User is signed in.
      var displayName = user.displayName;
      var email = user.email;
      var emailVerified = user.emailVerified;
      var photoURL = user.photoURL;
      var isAnonymous = user.isAnonymous;
      var uid = user.uid;
      var providerData = user.providerData;

      var ref = firebase.database().ref("users/" + uid);
      ref.once("value").then(function(snapshot) {
        username = snapshot.child("username").val();
        alert(username);
      });
      alert(username);
    }
  });
}
alert(username);

window.onload = function() {
  initApp();
};

I understand this may seem similar to other questions, but those answers didn't seem to work despite numerous different approaches. Thanks in advance for all of your help, I am hoping this is just a stupid mistake.

Answers:

Answer

I think you are confused about the asynchronous nature of your code. Your username is only going to be available in the callback here:

ref.once("value").then(function(snapshot) {
  username = snapshot.child("username").val();
  alert(username);
});

because ref.once("value") is asynchronous (the alert immediately following the code block above will always be called before your .then callback executes). Any code that depends on username is going to have to ensure that the asynchronous call is complete before executing.

There are a number of ways to accomplish this, such as: async/await, returning a Promise from your initApp function, or changing initApp to accept a callback that runs your dependent code once the async stuff is complete. Here is an example that returns a Promise:

function initApp() {
  return new Promise(function(resolve, reject) {
    // Listen for auth state changes.
    // [START authstatelistener]
    firebase.auth().onAuthStateChanged(function(user) {
      if (user) {
        // User is signed in.
        var displayName = user.displayName;
        var email = user.email;
        var emailVerified = user.emailVerified;
        var photoURL = user.photoURL;
        var isAnonymous = user.isAnonymous;
        var uid = user.uid;
        var providerData = user.providerData;

        var ref = firebase.database().ref("users/" + uid);
        ref.once("value").then(function(snapshot) {
          username = snapshot.child("username").val();
          resolve(username);
        });
      } else {
        // no username, reject
        reject("User is not logged in")
      }
    });
  });
}

window.onload = function() {
  initApp().then(function(username) {
    alert(username);
    // do things that depend on user/username
  }).catch(function(error) {
    alert(error);
  });
};

Once the Promise is in place, you can use async/await to make your code feel more synchronous:

window.onload = async function() {
  try {
    const username = await initApp();
    alert(username);
  } catch(e) {
    alert(e);
  }
};

Keep in mind that you will still not be able to alert the username outside of this function - any code that relies on the async data must wait until that data is ready i.e. be handled in a then/callback/etc.

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.