Reputation: 12816
I have the following Javascript object:
data = {
"Q1": [1,2,3,2],
"Q2": [5,6,7,6],
"Q3": [9,10,11,10]
};
From this I am trying to generate the following Table:
+----------+---------+--------+
| Question | Options | Answer |
+----------+---------+--------+
| Q1 | 1 | 2 |
+ +---------+ +
| | 2 | |
+ +---------+ +
| | 3 | |
+----------+---------+--------+
| Q2 | 5 | 6 |
+ +---------+ +
| | 6 | |
+ +---------+ +
| | 7 | |
+----------+---------+--------+
| Q3 | 9 | 10 |
+ +---------+ +
| | 10 | |
+ +---------+ +
| | 11 | |
+----------+---------+--------+
Here is the logic to converting the Javascript object to the table:
The key of the dictionary goes under column question
, the first 3 values in the array of the value corresponding to the key goes under column options
, the last value in the array goes under column answer
.
For example, the first key value pair in the object is
"Q1": [1,2,3,2]
Q1
goes under column Question
and the last value in the array [1,2,3,2]
goes under the column Answer
, the remaining three values in the array become three individual rows under the column Options
.
+----------+---------+--------+
| Question | Options | Answer |
+----------+---------+--------+
| Q1 | 1 | 2 |
+ +---------+ +
| | 2 | |
+ +---------+ +
| | 3 | |
+----------+---------+--------+
Here is what I tried:
Same snippet pasted below:
data = {
"Q1": [1,2,3,2],
"Q2": [5,6,7,6],
"Q3": [9,10,11,10]
};
//console.log(data);
var tbody = document.getElementById('tbody');
tbody.innerHTML += "<tr>" +
"<th id='q'>" + "Question" + "</th>" +
"<th id='o'>" + "Options" + "</th>" +
"<th id='ca'>" + "Correct Answer" + "</th>" +
"</tr>"
for (var question in data) {
var tr = "<tr>";
options = data[question];
answer = options.pop();
tr += "<td rowspan=" + options.length +" headers='q'>" + question + "</td>";
for(var index in options){
tr += "<td headers='o'>" + options[index] + "</td>"
}
tr += "<td headers='ca' rowspan=" + options.length + ">" + answer + "</td>" +
"</tr>"
tbody.innerHTML += tr;
}
<table class="table">
<tbody id="tbody"></tbody>
</table>
Upvotes: 1
Views: 3941
Reputation: 10719
Below codes should meet your requirements.
My solution:
loop the data first to re-shape your data, you can add some validators if necessary. (It seems the array includes options and answers, so assuming the last one always is the answer field), possible someone will feel this step is not neccessary, but what I thought is treat it as one adapter, for other different format data, we can create another adapter to format the data then doesn't need to modify the rest of the codes (generate HTML). Then add some validators will make the codes stronger.
then loop each item to generate the rows (HTML) (for Q1, Q2, Q3 etc), the trick is uses options.length as the rowspan value.
combine all HTMLs
data = {
"Q1": [1,2,3,2],
"Q2": [5,6,7,6],
"Q3": [9,10,11,10],
'Q4': [], // test case 1: no data
'Q5': [1], // test case 2: only answer field
'Q6': ['A', 'B', 'C'],// test case 3: for string
'Q7': ['TEST'] // test case 4: for answer(string) only
};
// For Q4, Q5, you can added some extra codes to uses default values intead, or ignore this row.
// formmat the data first, add some validators if neccessary
function formatAdapter (data) {
return Object.entries(data).map((item) => {
let newItem = {}
newItem[item[0]] = {'options': item[1].slice(0, item[1].length -1),
'answer': item[-1]} // assuming the last element is the answer, [0:last] is the options
return [item[0], item[1].slice(0, item[1].length -1), item[1].slice(-1)[0]]
})
}
let formmatedData = formatAdapter(data)
var tbody = document.getElementById('tbody');
// generate the header
tbody.innerHTML += "<tr>" +
"<th id='q'>" + "Question" + "</th>" +
"<th id='o'>" + "Options" + "</th>" +
"<th id='ca'>" + "Correct Answer" + "</th>" +
"</tr>"
// generate the rows(Html) for each questions
let rowHtmls = formmatedData.map((item) => {
let row = '<tr><td rowspan="'+(item[1].length || 1) +'">'+item[0]+'</td>'
+ '<td>'+item[1][0]+'</td>'
+ '<td rowspan="'+(item[1].length || 1)+'">'+item[2]+'</td></tr>'
row += item[1].slice(1).reduce((pre, cur) => {
return pre + '<tr><td>'+cur+'</td></tr>'
}, '')
return row
})
// combine header(html) and rows(html)
tbody.innerHTML += rowHtmls.reduce((pre, cur) => {
return pre+cur
}, '')
table tbody tr td {
border: 1px solid black
}
<table class="table">
<tbody id="tbody"></tbody>
</table>
Upvotes: 2