1

I am trying to create a Student Attendance Tracker Application with javascript with firebase.

But i have a problem, I am trying to query inside a function and have the function return those data.

But when i try, it returns nothing. 'undefined'

Here is my code

var root = 'https://path.firebaseio.com';
function initFireSubjects(){
   var db = {};
   db.connection = new Firebase(root + '/subjects');
   db.addSubject = function (year, code, name) {
       this.connection.child(year).push({
           code: code,
           name: name
       });
    };
    db.getAll = function (year) {
        var value;
        this.connection.child(year).on('value', function (snapshot) {
            value = snapshot.val();
        });
        return value;
    };
}

And here is my code to test it

var db = initFireSubjects();
var test = db.getAll('2014');
console.log(test);

The structure of the data looks like this

subject:{
    '2014':{
        randomKey1:{
            code:'eng1',
            name:'English 1'
        },
        randomKey2:{
            code:'math1',
            name:'Mathematics 1'
        },
        randomKey3:{
            code:'sci1',
            name:'Science 1'
        }
    },
    '2015':{
        randomKey4:{
            code:'polsci1',
            name:'Political Science 1'
        },
        randomKey5:{
            code:'comprog',
            name:'Computer Programming'
        }
    }
}

The case is i can pull data if i do it like this

db.getAll = function(year){
    var value;
    this.connection.child(year).on('value',function(snapshot){
        value = snapshot.val();
        console.log(value);
    }
}

I don't know why it can't pull data in an object oriented manner.

Any input?

Thanks.

Chum H
  • 47
  • 7

1 Answers1

4

What you're seeing has little to do with OO, but everything with the fact that Firebase is (like most of the modern web) asynchronous in nature.

When you register an event handler with Firebase using on, Firebase starts to retrieve and monitor the data at that location. Since it may take some time to retrieve the data (and updated data may arrive at any time) the browser continues executing your JavaScript. Once the data is available, your callback function is invoked.

It is a bit easier to see what's happening if we write your code slightly differently:

/* 1 */ db.getAll = function (year) {
/* 2 */     var value;
/* 3 */     this.connection.child(year).on('value', db.onValue);
/* 4 */     return value;
/* 5 */ };
/* 6 */ db.onValue = function(snapshot) {
/* 7 */     value = snapshot.val();
/* 8 */     console.log(value);
/* 9 */ });

When your getAll function executes, it declares a value variable first. In line 3 it then tells Firebase to call db.onValue when it gets a value for the year from the server. Firebase goes off to retrieve that value, but your JavaScript continues to execute. So in line 4 you then return value, which is still uninitialized. So you're returning undefined.

At some point the value you've asked for comes back from Firebase's servers. When that happens, the onValue function is invoked and it prints out the year in line 8.

One thing that may help you accept why this is useful: if another now updates the year in your Firebase, the onValue function will be invoked again. Firebase doesn't just retrieve the data once, it monitors the location for changes in the data.

The asynchronous loading is not unique to Firebase. Pretty much everyone that gets started programming for the modern web in JavaScript gets bitten by this at some point. The best thing you can do is accept and embrace the asynchronicity (is that even a word?) quickly and deal with it.

Dealing with it, usually means that you move the operation that you want to execute with the new values to inside the callback function. So the console.log that I added in line 8, could also be updating your UI with something like document.querySelector('#currentyear').textContent = value.

Also read this answer (it is using AngularFire, but the problem is the same): Asynchronous access to an array in Firebase and some of the other questions linked from there.

Community
  • 1
  • 1
Frank van Puffelen
  • 418,229
  • 62
  • 649
  • 645
  • You're welcome. If an answer is useful, vote for it by pressing the up-arrow please. If it answer your question, accept the answer by clicking the checkmark that is next to it. – Frank van Puffelen Feb 07 '15 at 14:43