feat(frontend): Vue can now interact with the chosen answers for questions.
This commit is contained in:
parent
6d452c7f72
commit
63d1ed8bd2
6 changed files with 99 additions and 1 deletions
|
@ -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>
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
5
frontend/src/views/learning-paths/gift-adapters/gift-adapter.d.ts
vendored
Normal file
5
frontend/src/views/learning-paths/gift-adapters/gift-adapter.d.ts
vendored
Normal 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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue