0

I'm attempting to check for a user before saving them in the firebase users table, but when I go to check using the .once() firebase method, the function always returns false...

When I console.log inside the function, it logs correctly, however it never returns true.

Auth Represents a basic Firebase Auth Factory

var newUser = function(id) {
  ref.child('users').child(id).once('value', function(snapshot) {
    console.log(snapshot.val() === null);
    return (snapshot.val() === null);
  });
};

Auth.$onAuth(function(authData) {
  console.log(Boolean(newUser(authData.uid)));
  if (authData && !!(newUser(authData.uid))) { // add user if first time login
    $scope.authData = authData;
    ref.child('users').child(authData.uid).$save({
      provider: authData.uid,
      name: getName(authData),
      blah: 'blah'
    });
    $state.go('main.home');
  } else if (authData) {
    $state.go('main.home');
  } else {
    console.log('Not Logged In');
  }
});
Joseph Williams
  • 85
  • 1
  • 15

1 Answers1

0

Your new user function doesn't return anything. Maybe it will help you to see if it you move your callback function out into it's own named function.

var onValue = function(snapshot) {
  console.log(snapshot.val() === null);
  return (snapshot.val() === null);    
};

var newUser = function(id) {
  ref.child('users').child(id).once('value', onValue);
  // new user doesn't return anything
};

When you omit a return value, the function will automatically return undefined, which you are coercing to a boolean — resulting in false.

The problem here is that the callback for Firebase's .once method runs after your function (fails to) return a value. This is because it is asynchronous.

This is a fairly common problem for new Javascript developers, but can be easily visualized with a small example.

function doAsync() {
  setTimeout(function() {
    console.log('a');
    return 'a';
  }, 3000);

  console.log('b');
  return 'b';
}
doAsync();

What order would you expect the console.log statements to run? Which value would you expect the function to return? If it's not obvious, spend some time experimenting with the code in your console.

Obviously, it's still important to be able to get values out of async functions. One way to do this is with callback functions.

In your case, you would add a callback parameter to your new user function, then call that function with the new user as soon as it is available.

var newUser = function(id, done) {
  ref.child('users').child(id).once('value', function(snapshot) {
    done(snapshot.val() === null);
  });
};

Then amend your other code to work with this style.

Auth.$onAuth(function(authData) {
  newUser(authData.uid, function(val) {
    // do something with the result
  });
});
Dan Prince
  • 29,491
  • 13
  • 89
  • 120
  • Thanks, Dan! I ended up putting it into a promise and checking the data after the promise resolves. Very good explanation of what was going on in Javascript. – Joseph Williams Jan 07 '16 at 20:30