0

I am trying to return return a value and display it in the console.(for now) The user ID is passed to a "function". The function will check for this ID in a database and should return the userName. I know that the correct data is found because the console.log returns the correct infirmation in function itself (see: THIS WORKS) But the returned value is "undefined" when used return childData.userName;

Calling the function

console.log( f_returnUserDetails(uid)

The function itself

  function f_returnUserDetails(a){
    console.log(a)
    var key;
    var childData;
    firebase.database().ref('/dataman-blabla/').orderByChild("uid").equalTo(a).on('value', function (snapshot) {
      snapshot.forEach(function(childSnapshot) {
          key = childSnapshot.key;
          childData = childSnapshot.val();
          console.log(childData.userName); //THIS WORKS
          return childData.userName; //THIS DOES NOT
      });
    });
  };
MK01111000
  • 770
  • 2
  • 9
  • 16

3 Answers3

1

You have to return promise because this function is asynchronous.

    function f_returnUserDetails(a){
      console.log(a)
      var key;
      var childData;
      return new Promise(function(resolve, reject) { //return promise
        firebase.database().ref('/dataman-blabla/').orderByChild("uid").equalTo(a).on('value', function (snapshot) {
          snapshot.forEach(function(childSnapshot) {
            key = childSnapshot.key;
            childData = childSnapshot.val();
            console.log(childData.userName);
            resolve(childData.userName); 
          });
        });
      });
    };
   // function call should be like this   
   f_returnUserDetails(uid).then((username) => {
     console.log(username);
   });
Saad Mehmood
  • 691
  • 1
  • 7
  • 19
  • This returns in the following `Promise {} __proto__: Promise catch: ƒ catch() constructor: ƒ Promise() finally: ƒ finally() then: ƒ then() Symbol(Symbol.toStringTag): "Promise" __proto__: Object [[PromiseStatus]]: "pending" [[PromiseValue]]: undefined` – MK01111000 Oct 26 '18 at 09:32
  • It's a promise. It's supposed to look like that. An asynchronous function cannot sensibly return anything else (unless it allows a callback). – Amadan Oct 26 '18 at 09:34
  • make sure you adding ```.then``` after function call – Saad Mehmood Oct 26 '18 at 09:35
  • you will get your response in ```.then``` callback – Saad Mehmood Oct 26 '18 at 09:36
  • Please forgive my ignorance, this is new to me. How do I extract the value from the promise? – MK01111000 Oct 26 '18 at 09:36
  • You might want to read this canonical question: [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) – Amadan Oct 26 '18 at 09:37
  • Seems that instead of `on('value', callback)`, you can do `once('value').then(...)`, which lets you not mess with `Promise` constructor for a bit simpler code (also, this is wasteful given that the handler will hang on and try to resolve a resolved promise each time the value event triggers subsequently, which is a memory leak; not your fault, OP has the same problem) – Amadan Oct 26 '18 at 09:47
  • @Saad Mehmood,I needed some time to see how this all works. Your code was the solution and got it all working now.Thanks! – MK01111000 Oct 26 '18 at 10:18
  • @MK01111000 i am glad that it help or atleast it give you a direction. best of luck – Saad Mehmood Oct 26 '18 at 11:04
0

I am not 100% sure but I think .forEach does not play nice with breaks and returns. Try changing it to a traditional for of loop and see if that works.

Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Description

There is no way to stop or break a forEach() loop other than by throwing an exception. If you need such behavior, the forEach() method is the wrong tool.

return firebase.database().ref('/dataman-blabla/').orderByChild("uid").equalTo(a).on('value', function (snapshot) {
      for(childSnapshot of snapshot) {
          key = childSnapshot.key;
          childData = childSnapshot.val();
          console.log(childData.userName); //THIS WORKS
          return childData.userName; //THIS DOES NOT
      });
    });
  • The console.log returns the correct value though (only the correct one) – MK01111000 Oct 26 '18 at 09:35
  • How do you mean return? It just logs the value in the console. It doesn't pass it back. I also think you need to add return to the firebase call. See my updated answer. –  Oct 26 '18 at 09:39
  • Callbacks and promises are kind of an either-or situation. `on` will trigger a callback every time; the return value of a callback cannot be used. `once` will return a promise which will fulfill at the first instance of that event, and will pass the value to `then` handler, which you can then chain into a new promise by returning a value from the `then` handler. – Amadan Oct 26 '18 at 09:45
  • @B.Blunt your code returns the following: `ƒ (snapshot) { for(childSnapshot of snapshot) { key = childSnapshot.key; childData = childSnapshot.val(); console.log(childData.userName); //THIS WORKS ` – MK01111000 Oct 26 '18 at 09:52
0

Call new function and pass the response

function f_returnUserDetails(a){
    console.log(a)
    var key;
    var childData;
    firebase.database().ref('/dataman-blabla/').orderByChild("uid").equalTo(a).on('value', function (snapshot) {
      snapshot.forEach(function(childSnapshot) {
          key = childSnapshot.key;
          childData = childSnapshot.val();
          console.log(childData.userName); //THIS WORKS
          processData(childData.userName); 
      });
    });
  };


function processDate(name){
   // You have your name here.
}
jsduniya
  • 2,464
  • 7
  • 30
  • 45