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 } }