I am trying to get a forEach loop to write a table row that consists of a variable from both a shallow nested object and a deep nested object.
I have this JSON object:
var chardata = [{
"moveList": [{
"name" : "Directional Tests",
"synergy" : [{ "partner" : "Character A", "moveEqual" : "Direct Synergy for A" }, { "partner" : "Character B", "moveEqual" : "Direct Synergy for B" }]
},{
"name" : "Motion Tests",
"synergy" : [{ "partner" : "Character A", "moveEqual" : "Motion Synergy for A" }, { "partner" : "Character B", "moveEqual" : "Motion Synergy for B" }]
},{
"name" : "Button Tests",
"synergy" : [{ "partner" : "Character A", "moveEqual" : "Button Synergy for A" }, { "partner" : "Character B", "moveEqual" : "Button Synergy for B" }]
}]
}];
And this forEach function:
function buildSynergyTest(data) {
var table = document.getElementById('CharacterSynergy');
var html = 'n';
for (character of data) {
character.moveList.forEach(function(move, i) {
html += ` <TR>n`;
html += ` <TD>${move.name}</TD>n`;
html += ` <TD>${move.synergy[i].partner}</TD>n`;
html += ` <TD>${move.synergy[i].moveEqual}</TD></TR>n`;
});
}
table.innerHTML += html;
}
buildSynergyTest(chardata);
When I run the forEach loop, the first column translates perfectly. But the second and third columns do not. What’s supposed to happen is this:
<TABLE border=1>
<TR>
<TD>Directional Test</TD>
<TD>Character A</TD>
<TD>Direct Synergy for A</TD></TR>
<TR>
<TD>Motion Test</TD>
<TD>Character A</TD>
<TD>Motion Synergy for A</TD></TR>
<TR>
<TD>Button Test</TD>
<TD>Character A</TD>
<TD>Button Synergy for A</TD></TR>
<TR>
<TD>Directional Test</TD>
<TD>Character B</TD>
<TD>Direct Synergy for B</TD></TR>
<TR>
<TD>Motion Test</TD>
<TD>Character B</TD>
<TD>Motion Synergy for B</TD></TR>
<TR>
<TD>Button Test</TD>
<TD>Character B</TD>
<TD>Button Synergy for B</TD></TR></TABLE>
Instead, I am getting one of two results:
-
The second and third columns of data (move.synergy.partner and move.synergy.moveEqual) are listed as undefined. But they are defined, all I have to do is a console.log of chardata[0].moveList[0].synergy[0].partner/moveEqual, and they would show up just fine.
-
If I were to put the [i] symbol in front of synergy, JS breaks with an undefined error. I know that [i] works in for loops, so I have to assume it should also work in this forEach, but for some reason it doesn’t.
The only way I can bring up the desired values is hard coding, by deliberating putting a [0] or [1], but that defeats the purpose of the forEach loop.
How do I rewrite the forEach loop so that it can iterate all columns to be like the expected example?
3
Answers
You need one more loop
Also, may be easier using
map
You need a second for the synergy entries.
Important notice: never use
innerHTML+=
since it re-writes DOM entirely leading to slow performance plus broken event handlers, etc.Here is another way of doing it:
In the first
.flatMap()
loop I collect all the nested subarrays into a flat array and re-arrange them slightly: the propertyname
is inserted as a first element of the returned array, followed by thepartner
andmoveEqual
properties of the array in thesynergy
property.The
.sort()
then sorts the array according to the second column ("Character A/B"). As the JavaScript sort function is now stable the original order of Directional, Motion and Button test is maintained.The
.map()
following the sort then creates some HTML that is evetually.join()
ed with a newline character and assigned to the.innerHTML
of the first table in the document (feel free to insert an#id
selector here instead).