I’m working on a script that would be a marksheet-type thing where teachers would simply click through questions and it would calculate scores for students and generate stats for the whole class/group.
I want to display data from nested objects that are templates for different types of tests, reflecting their structure: the number of parts, the number of questions in each part and the number of points exam takers can get for a correct answer. I need a function that would work with all of these templates.
Here is a shortened but hopefully clear example:
const b1listening = {
testName: 'PET Listening',
maxScore: 25,
totalscore: null,
testStructure: [
{
partNumber: 1,
taskType: 'Three-option multiple choice',
partscore: null,
questions: [
{
questionNumber: 1,
value: 1,
score: null
},
{
questionNumber: 2,
value: 1,
score: null
},
// ...
{
questionNumber: 7,
value: 1,
score: null
}
]
},
{
partNumber: 2,
taskType: 'Three-option multiple choice',
partscore: null,
questions: [
{
questionNumber: 8,
value: 1,
score: null
},
// ...
{
questionNumber: 12,
value: 1,
score: null
},
{
questionNumber: 13,
value: 1,
score: null
}
]
},
{
partNumber: 3,
taskType: 'Gap fill',
partscore: null,
questions: [
{
questionNumber: 14,
value: 1,
score: null
},
{
questionNumber: 15,
value: 1,
score: null
},
// ...
{
questionNumber: 19,
value: 1,
score: null
}
]
},
{
partNumber: 4,
taskType: 'Three-option multiple choice',
partscore: null,
questions: [
{
questionNumber: 20,
value: 1,
score: null
},
// ...
{
questionNumber: 25,
value: 1,
score: null
}
]
}
]
};
See all of the templates here
Wherever there is an array within the main object (see partNumber
and questionNumber
) that means there might be a variable number of those across different templates. Scoring is variable as well: with some questions it’s either 1 point or 0, with others it’s 2 or 0 and with others it’s 1 or 2 or 0.
Here is the function I managed to put together:
function buildOutput(obj) {
const marksheet = document.querySelector('.marksheet');
marksheet.innerHTML =
`
<h1>${obj.testName}</h1>
<h1>${obj.date} – ${obj.class}</h1>
<h2 class="block">${obj.studentName} – TOTAL: <span class="scores">${obj.totalScore} / ${obj.maxScore}</span></h2>
${Object.values(obj.testStructure)
.map(val =>
`
<h3 class="block">PART ${val.partNumber} ${val.taskType} <span class="scores">${val.partScore}</span></h3>
${Object.values(val.questions)
.map(qn =>
val.partNumber === 4 && val.taskType === 'Key word transformation'
? `<p>
<span class="qn-number">${qn.questionNumber}</span>
<button class="button btn-incorrect">0</button>
<button class="button btn-one">1</button>
<button class="button btn-two">2</button>
<span class="scores">${qn.score === null ? `▲` : qn.score}</span>
</p>`
:
`<p>
<span class="qn-number">${qn.questionNumber}</span>
<button class="button btn-incorrect">X</button>
<button class="button btn-correct">✓</button>
<span class="scores">${qn.score === null ? `▲` : qn.score}</span>
</p>`
).join("")
}
`
).join("")
}
`
};
It seems to work but to be honest it’s the outcome of trial and error rather than anything else. Any comments appreciated.
Levente