gbm0102
gbm0102

Reputation: 109

Firebase - Retrieving and storing data in array with callbacks

I'm want to use Firebase callbacks to retrieve data from my realtime database, store it in an array, then use that data for data visualization purposes. But when I log the console for the array, it returns empty. I referenced this post in an attempt to understand/fix my error, but I'm still having a lot of trouble.

var genderData=[];
// Get counter values.
function getData(){
    var ref = firebase.database().ref().child('counters');

    return ref.once('value').then((snapshot) => {
        snapshot.forEach((element) => {
            genderData.push(element.val()['Male']);
        });
        return genderData;
    });
}

console.log(genderData);

My console shows:

enter image description here

Eventually, I want to be able to use my array to produce a chart with the Chart.js library:

// Bar graph displaying the total number of students by gender.
var ctx = document.getElementById("myChart4").getContext('2d');
var myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ["Male", "Female", "Non-Binary", "Other", "Unspecified"],
        datasets: [{
            data: genderData,
            backgroundColor: [
                'rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 206, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)',
                'rgba(255, 159, 64, 0.2)',
            ],
            borderColor: [
                'rgba(255,99,132,1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 206, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)',
                'rgba(255, 159, 64, 1)'
            ],
            borderWidth: 1
        }]
    },
    options: {
        title: {
            display: true,
            text: 'Total Students by Gender'
        },
        legend:{
            display: false
        },
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero:true
                }
            }]
        }
    }
});

I've been working on this problem for hours, with no solution. All I want is to create a simple array with my database data, but I've had so much trouble. I really hope someone can help me find an elegant solution.

EDIT:

A bit of my database structure, just in case:

enter image description here enter image description here

Upvotes: 0

Views: 144

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598728

Firebase loads data asynchronously. This means that any code that needs access to the data, must be inside the then() callback, or must use a then() callback of its own.

With your current definition of getData, you can call it and use the data with:

getData().then((data) => {
  console.log("In callback");
  console.log(data);
  console.log(genderData);
})
console.log("Outside callback");
console.log(genderData);

If you run this code, you'll see:

Outside callback

[]

Inside callback

[ item1, item2, ... ]

[ item1, item2, ... ]

The things to note here:

  1. the Outside callback code runs before the Inside callback code, which is probably not what you expected.
  2. the code outside of the callback runs, the array is still empty. Only once the code inside the callback has run, does the array contain data.
  3. inside the callback, the genderData and the data are the same. This is because you return genderData in the callback, which is then bubbled up to the then() method.

The final solution for you is that the code that creates the chart (which is where you need the data), should be inside one of the then callbacks so that it gets called once the data has loaded. For example:

getData().then((data) => {
   var myChart = new Chart(ctx, {
     type: 'bar',
     data: {
        labels: ["Male", "Female", "Non-Binary", "Other", "Unspecified"],
        datasets: [{
            data: data,
            ... 

Upvotes: 2

Related Questions