1

I'm working on an Angular application and want to get some data from Firestore. But my function always returns undefined. When I, however, console.log() the value before returning it, it displays the correct value.

getToken(user_id) {
    this.afs.collection("tokens").ref.doc(user_id).get().then((doc) => {
      if (doc.exists) {
        console.log(doc.data().user_token); //displays the correct user_token value
        return doc.data().user_token; //returns undefined!
      }
    });
}

Shouldn't both values be the same?

Ian
  • 5,704
  • 6
  • 40
  • 72
  • You aren't returning the actual promise. Put a `return` in front of `this.afs.collection("tokens")`. Also please show how you are consuming `getToken()`. – Alexander Staroselsky May 29 '19 at 16:53

2 Answers2

2

It appears that you are not returning the Promise from your function - there is no return statement in the getToken function at all, so the function itself just returns undefined. The internal return statement you have will resolve the promise, which is good, but you have to handle that resolution.

If you return the promise like so:

getToken(user_id) {
    return this.afs.collection("tokens").ref.doc(user_id).get().then((doc) => {
      if (doc.exists) {
        console.log(doc.data().user_token); //displays the correct user_token value
        return doc.data().user_token;
      }
    });
}

You should be able to access the user_token asynchronously when the promise resolves by doing the following:

getToken(user_id).then(user_token => {
  handle_user_token_here(user_token);
});

Note: The function as modified will return a promise. Therefore, you cannot simply the following:

let user_token = getToken(user_id);
// user_token here is a Promise object, not the token!
handle_user_token_here(user_token); // will not work.

You can do this though:

let user_token = getToken(user_id);
// user_token here is a Promise object, not the token!
user_token.then(user_token => handle_user_token_here(user_token)); // will work
Ian
  • 5,704
  • 6
  • 40
  • 72
  • I tried this: `getToken(user_id).then(user_token => { let token = user_token.data.user_token; });` but when I log token, it still returns undefined – Mathias Riedel May 29 '19 at 17:06
  • Where did you log the token? If you did this: `getToken(user_id).then(user_token => { let token = user_token.data.user_token; console.log(token); });` it should work (assuming you modified `getToken` by adding the return statement). If you did this: `getToken(user_id).then(user_token => { let token = user_token.data.user_token; }); console.log(token);` you would be trying to use `token` outside the function scope and that won't work. – Ian May 29 '19 at 18:06
  • I actually did this: `token:any; signInSuccess() { this.tokenService.getToken(user_id).then((user_token) => { this.token = user_token.data().user_token; }); console.log(this.token); }` (Everything inside the HomePage class in a home.page.ts file) – Mathias Riedel May 29 '19 at 18:09
  • And yes, I did modify `getToken()` the way way you suggested – Mathias Riedel May 29 '19 at 18:15
  • That still won't work, as `getToken` (and any function involving promises) is asynchronous. You are accessing `this.token` after assigning it in the code, but not after the `Promise` resolves. The `Promise`could take several seconds to resolve, and in order to not stop all your code while waiting for a request to finish, the code continues immediately. – Ian May 29 '19 at 18:23
  • Here's an example that explains it better than I can https://jsfiddle.net/6eq7ndxu/. Run the code and open your browser console and note what order the log statements appear and with what payloads. – Ian May 29 '19 at 18:24
0

This may answer your question: Can't access object property, even though it exists. Returns undefined

"The output of console.log(anObject) is misleading; the state of the object displayed is only resolved when you expand the > in the console."

In other words, doc.data().user_token might be getting populated by an asynchronous process.