75 lines
2.2 KiB
JavaScript
75 lines
2.2 KiB
JavaScript
import { Controller } from '@hotwired/stimulus'
|
|
|
|
/*
|
|
* Shows a questionnaire question only while its show_if holds, mirroring
|
|
* App\Model\Questionnaire\Definition::isVisible(): the condition must be met and the question it
|
|
* depends on must itself be shown.
|
|
*
|
|
* Every question row carries data-question-key; a conditional one also data-show-if, the JSON
|
|
* {question, operator, value} that App\Form\QuestionnaireType writes. A hidden row stays in the
|
|
* form and is submitted: a draft keeps its answer, and the server drops it on submit.
|
|
*/
|
|
export default class extends Controller {
|
|
|
|
connect() {
|
|
this.update()
|
|
}
|
|
|
|
update() {
|
|
const visible = {}
|
|
|
|
// Rows come in definition order, and a condition may only name an earlier question, so
|
|
// the question a row depends on has always been decided by the time the row is reached.
|
|
for (const row of this.element.querySelectorAll('[data-question-key]')) {
|
|
const key = row.dataset.questionKey
|
|
const condition = row.dataset.showIf ? JSON.parse(row.dataset.showIf) : null
|
|
|
|
visible[key] = null === condition
|
|
|| (true === visible[condition.question] && this.isMet(condition))
|
|
|
|
row.hidden = false === visible[key]
|
|
}
|
|
}
|
|
|
|
isMet({ question, operator, value }) {
|
|
const answer = this.answer(question)
|
|
|
|
if (null === answer) {
|
|
return false
|
|
}
|
|
|
|
switch (operator) {
|
|
case 'equals':
|
|
return answer === value
|
|
case 'in':
|
|
return value.includes(answer)
|
|
case 'lte':
|
|
return Number(answer) <= value
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
answer(key) {
|
|
const row = this.element.querySelector(`[data-question-key="${key}"]`)
|
|
|
|
if (null === row) {
|
|
return null
|
|
}
|
|
|
|
const checked = row.querySelector('input[type="radio"]:checked')
|
|
|
|
if (null !== checked) {
|
|
return checked.value
|
|
}
|
|
|
|
const select = row.querySelector('select')
|
|
|
|
if (null !== select) {
|
|
return '' === select.value ? null : select.value
|
|
}
|
|
|
|
return null
|
|
}
|
|
}
|