はじめに
現在筆者は、Laravel8(php8.1), inertia.js(Vue3,JavaScript)で開発をしております。
Vue3 <script setup> 構文で孫、子、親のバケツリレーを書いてみた。 の記事を参考にさせていただき実装してみたので、自分なりに解釈した内容を添えてソースコードをご紹介します。
ソースコード
孫コンポーネント
v-modelに値を渡す実際の処理の記述
<script setup>
const props = defineProps([
"id",
"value",
"text",
"modelValue",
]);
// 子に渡すトリガー名の総称をemitという名前で定義
const emit = defineEmits(["update:modelValue"]);
// templateの中で式を書くと読みにくくなるのでこの位置で呼び出す処理を準備
const updateValue = (e) => {
// 子要素のmodelValueをe.target.valueでupdate
emit("update:modelValue", e.target.value);
};
</script>
<template>
<input
:id="id"
type="radio"
:value="value"
:checked="value == modelValue"
@change="updateValue"
/>
<label :for="id" class="radio__text"> {{ text }}</label>
</template>
子コンポーネント
親に書くと冗長になるので切り出した記述
<script setup>
import RadioButton from "@/Components/atoms/forms/RadioButton.vue";
const props = defineProps([
"questionnaire_content",
"answer_option",
"question",
"question_number",
"modelValue",
]);
// 親に渡すトリガー名の総称をemitという名前で定義
const emit = defineEmits(["update:modelValue"]);
// templateの中で式を書くと読みにくくなるのでこの位置で呼び出す処理を準備
const updateValue = (e) => {
// 親要素のmodelValueをeでupdate
// この場合のeは孫要素が渡した引数と同じになるので、孫のe.target.valueになります。
// なので下記の引数はe.target.valueにならないので注意が必要です。
emit("update:modelValue", e);
};
</script>
<template>
<div>Q{{ question_number }}.</div>
<div>{{ question }}</div>
<RadioButton
v-for="(value, key) in answer_option[questionnaire_content.id]"
:id="'q' + questionnaire_content.id + '.' + key"
:value="key"
:text="value"
:modelValue="modelValue" ← 忘れずに渡してください
@update:modelValue="updateValue" ← "update:modelValueが孫コンポーネントで呼び出されたら、子でupdateValueを実行する"という内容になってます。
></RadioButton>
</template>
親コンポーネント
できるだけスッキリ書いた記述(実際に実装したものではformなどの記述もありますが、今回は関係ない部分は端折ってあります。)
<script setup>
import Question from "@/Components/molecules/User/FreeTrial/Questionnaire/Question.vue";
import { reactive } from "vue";
import { useForm } from "@inertiajs/inertia-vue3";
// laravelから受け取ったdbのレコード(object)
const props = defineProps(["questionnaire_contents", "user"]);
// 表示に使う値を準備
let prepare_answer_option = {};
for (const questionnaire_content of props.questionnaire_contents) {
prepare_answer_option[questionnaire_content.id] = {};
for (const key in JSON.parse(questionnaire_content.answer_option)) {
prepare_answer_option[questionnaire_content.id][key] = JSON.parse(
questionnaire_content.answer_option
)[key];
}
}
const answer_option = reactive(prepare_answer_option);
// v-modelで使う変数を用意
const form = useForm({
q1: "",
});
</script>
<template>
<Question
:question_number="1"
:questionnaire_content="questionnaire_contents[0]"
:answer_option="answer_option"
:question="questionnaire_contents[0].question"
v-model="form.q1" ←modelValueの定義と@update:modelValueの総称。親コンポーネントだけで使えるっぽい
></Question>
</template>
以上になります。