The ultimate goal is to create a d3 stacked diverging bar chart. The votesData object is created successfully from the data, but I can only access the data within the d3 then function even though the array is created outside of it?
Code:
var votesData = []; //access votes route d3.json("/votes").then(function (data) { //loop through objects in route data.forEach(function (d) { //convert data to numeric demYes = +d.democratic.yes demNo = ~d.democratic.no //makes negative repYes = +d.republican.yes repNo = ~d.republican.no indYes = +d.independent.yes indNo = ~d.independent.no //append var with desired data votesData.push( {"name": d.bill.bill_id, "question": d.question, "description": d.description, "votes": [ {"category": "Democratic Yes", "value": demYes }, {"category": "Democratic No", "value": demNo}, {"category": "Republican Yes", "value": repYes}, {"category": "Repulican No", "value": repNo}, {"category": "Independent Yes", "value": indYes}, {"category": "Independent No", "value": indNo} ] }) }); console.log(votesData); console.log(votesData[0]); }); console.log(votesData); console.log(votesData[0]);
The first set of logs return the array and the first object as expected but the second set of logs (outside the d3 then) return the votesData object, but when trying to access the first index of the object it returns “undefined”. Why? And how would I iterate through that object outside of the d3 then function? Or should I just append everything needed in the svg area within that function?
Advertisement
Answer
The logic inside the then
block is asynchronous. What that means it’s scheduled to be executed when the thread has time, and the promise to read a /votes
file has resolved. That means that the code is actually executed in the following order:
var votesData = []; console.log(votesData); console.log(votesData[0]); //access votes route d3.json("/votes").then(function (data) { ... });
That is why it returns undefined, it hasn’t been executed yet! The common workaround is to move all your logic inside the .then()
block, or, if you’re using ES2017 you can use async/await
.
var votesData = []; //access votes route const data = await d3.json("/votes"); //loop through objects in route data.forEach(function (d) { //convert data to numeric demYes = +d.democratic.yes ... } console.log(votesData); console.log(votesData[0]);
What this compiles to under water is equivalent to the .then()
solution, it’s just meant to make your coding experience easier.