0

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

gbm0102
  • 87
  • 8

1 Answers1

2

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,
            ... 
Community
  • 1
  • 1
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • This makes sense. But I think now I've run into a different problem: when I log the data as you suggested, all of my values are undefined (and there are far too many values -- 54 when there should be 13). What could be causing this? I've included a screenshot of my database structure, just in case. – gbm0102 Nov 23 '18 at 17:11
  • My guess is that you call `getData()` multiple times, and each time you add all items to `genderData`. But it's just a guess. Note that none of this has anything to do with the chart.js library itself, so I recommend looking at [how to create a minimal, complete, verifiable example](http://stackoverflow.com/help/mcve) to reduce the scope of the problem. – Frank van Puffelen Nov 23 '18 at 17:13
  • Yes, I believe it was the `forEach` loop. I removed it and simply did `genderData.push(snapshot.val()['Male']);`, and now my console seems to be logging as expected (I hope). Here is a screenshot: https://imgur.com/a/Dil6ojT – gbm0102 Nov 23 '18 at 17:17