0

I am trying to retrieve data from my database. My code creates an empty array and appends a child to it each time one is added. It then creates the list (ignore the MDL classes) and adds it to the HTML document.

<script>
    // get emergencies to array
    var firebaseRef = firebase.database().ref('Incidents');
    var emergencies = [];
    // var emergencies = ['Test', 'Test 2', 'Test 3'];

    firebaseRef.on('child_added', function(snap) {
        snap.forEach(function (childSnap) {
            console.log(childSnap.val());
            emergencies.push(childSnap.val());
        });
    });

    var opentag = '<ul class="mdl-list" id="emergenciesList">',
    closetag = '</ul>',
    array = [];

    for (i = 1; i <= emergencies.length; i++) {
        array[i] = '<li class="mdl-list__item">' + emergencies[i] + '</li>';
    }

    var newArray = array.join(" ");

    document.getElementById('foo').innerHTML = opentag + newArray + closetag;
</script>

The weird thing is, that at the console.log() statement, the data is retrieved perfectly fine, but after the string manipulation, newArray is undefined. Help!

1 Answer 1

1

The problem is caused by the way you've ordered your code. The order in which the lines are executed are not what you think. It's easiest to see this if you reduce it to this:

var firebaseRef = firebase.database().ref('Incidents');

console.log("Before database loading started");
firebaseRef.on('child_added', function(snap) {
  console.log("In child_added");
});
console.log("After database loading started");

Now the order in which the logging will be written is:

Before database loading started

After database loading started

In child_added

This is probably not what you expected. The reason the logging shows in this order is that Firebase loads the data asynchronously. So while the on('child_added' lines starts loading the data, it may take some time to get that data from the Firebase servers. Instead of waiting for the data (which would block the ability of your users to interact with your app), the browser continues to execute the statements after the block. Then when the data is available, it calls your callback function.

A common way of dealing with the asynchronicity is by reframing your problems. Right now your code is written as "first load the data, then add it to the HTML". Try instead framing it as "start loading the data. When the data is available, add it to the HTML". That translates into this code:

var firebaseRef = firebase.database().ref('Incidents');

firebaseRef.on('child_added', function(snapshot) {
    var ul = document.getElementById("emergenciesList");
    if (!ul) {
        document.getElementById('foo').innerHTML = '<ul class="mdl-list" id="emergenciesList"></ul>';
        ul = document.getElementById("emergenciesList");
    }
    var li = document.createElement("li");
    li.classList.append("mdl-list__item"); // or: li.className = "mdl-list__item"
    li.id = snapshot.key;
    li.innerText = snapshot.val();
    ul.appendChild(li);
});

I removed the loop over the snapshot, because I'm not sure it is needed and it complicates the code. If your data structure needs the loop, you can add it back where it was.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks so much! This makes a lot of sense. One issue though, it still doesn't work; I'm now receiving an error that "li.classList.append" is not a function. I have tried "li.className" as well. Why is that?
Interesting. Element.classList a relatively well supported DOM method. I added a more compatible alternative in a comment.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.