feat(frontend): Vue can now interact with the chosen answers for questions.

This commit is contained in:
Gerald Schmittinger 2025-04-16 13:02:13 +02:00
parent 6d452c7f72
commit 63d1ed8bd2
6 changed files with 99 additions and 1 deletions

View file

@ -3,6 +3,8 @@
import type { UseQueryReturnType } from "@tanstack/vue-query";
import { useLearningObjectHTMLQuery } from "@/queries/learning-objects.ts";
import UsingQueryResult from "@/components/UsingQueryResult.vue";
import {nextTick, onMounted, reactive, watch} from "vue";
import {getGiftAdapterForType} from "@/views/learning-paths/gift-adapters/gift-adapters.ts";
const props = defineProps<{ hruid: string; language: Language; version: number }>();
@ -11,6 +13,49 @@
() => props.language,
() => props.version,
);
const currentAnswer = reactive([]);
function forEachQuestion(
doAction: (questionIndex: number, questionName: string, questionType: string, questionElement: Element) => void
) {
const questions = document.querySelectorAll(".gift-question");
questions.forEach(question => {
const name = question.id.match(/gift-q(\d+)/)?.[1]
const questionType = question.classList.values()
.find(it => it.startsWith("gift-question-type"))
.match(/gift-question-type-([^ ]*)/)?.[1];
if (!name || isNaN(parseInt(name)) || !questionType) return;
const index = parseInt(name) - 1;
doAction(index, name, questionType, question);
});
}
function attachQuestionListeners() {
forEachQuestion((index, name, type, element) => {
getGiftAdapterForType(type)?.installListener(
element, (newAnswer) => currentAnswer[index] = newAnswer
);
});
}
function setAnswers(answers: (object | string | number)[]) {
forEachQuestion((index, name, type, element) => {
getGiftAdapterForType(type)?.setAnswer(element, answers[index]);
});
currentAnswer.fill(answers);
}
onMounted(() => nextTick(() => attachQuestionListeners()));
watch(learningObjectHtmlQueryResult.data, async () => {
await nextTick();
attachQuestionListeners();
setAnswers([1]);
});
</script>
<template>
@ -22,6 +67,7 @@
class="learning-object-container"
v-html="learningPathHtml.data.body.innerHTML"
></div>
{{ currentAnswer }}
</using-query-result>
</template>

View file

@ -0,0 +1,13 @@
export const essayQuestionAdapter: GiftAdapter = {
questionType: "Essay",
installListener(questionElement: Element, answerUpdateCallback: (newAnswer: string | number | object) => void): void {
const textArea = questionElement.querySelector('textarea')!;
textArea.addEventListener('input', () => answerUpdateCallback(textArea.value));
},
setAnswer(questionElement: Element, answer: string | number | object): void {
const textArea = questionElement.querySelector('textarea')!;
textArea.value = String(answer);
}
}

View file

@ -0,0 +1,5 @@
interface GiftAdapter {
questionType: string;
installListener(questionElement: Element, answerUpdateCallback: (newAnswer: string | number | object) => void): void;
setAnswer(questionElement: Element, answer: string | number | object): void;
}

View file

@ -0,0 +1,8 @@
import {multipleChoiceQuestionAdapter} from "@/views/learning-paths/gift-adapters/multiple-choice-question-adapter.ts";
import {essayQuestionAdapter} from "@/views/learning-paths/gift-adapters/essay-question-adapter.ts";
export const giftAdapters = [multipleChoiceQuestionAdapter, essayQuestionAdapter];
export function getGiftAdapterForType(questionType: string): GiftAdapter | undefined {
return giftAdapters.find(it => it.questionType === questionType);
}

View file

@ -0,0 +1,26 @@
export const multipleChoiceQuestionAdapter: GiftAdapter = {
questionType: "MC",
installListener(questionElement: Element, answerUpdateCallback: (newAnswer: string | number | object) => void): void {
questionElement.querySelectorAll('input[type=radio]').forEach(element => {
const input = element as HTMLInputElement;
input.addEventListener('change', () => {
answerUpdateCallback(parseInt(input.value));
});
// Optional: initialize value if already selected
if (input.checked) {
answerUpdateCallback(parseInt(input.value));
}
});
},
setAnswer(questionElement: Element, answer: string | number | object): void {
questionElement.querySelectorAll('input[type=radio]').forEach(element => {
const input = element as HTMLInputElement;
console.log(`input: ${input.value}, answer: ${answer}`);
input.checked = String(answer) === String(input.value);
console.log(input.checked);
});
}
}