[Vue3] コンポーネントにしてみる

JavaScript

CMSのようなシステムでアンケートを実装する時にチェックボックスなのかセレクトボックスなのか・・・動的に作りたいときとか。
こんな感じのセレクトボックスのコンポーネントを用意する

<template>
  <select class="form-control form-select" v-model="choice">
    <option disabled :value="initial">{{ initial.label }}</option>
    <option v-for="option in options" :key="option.id" :value="option">{{ option.label }}</option>
  </select>
</template>

<script setup lang="ts">
  import { Option, Answer } from '@/questionnaire'
  import { ref, watch } from 'vue'

  const props = defineProps<{
    userId: number
  }>()

  const options = defineModel<Option[]>('options')
  const choices = defineModel<Option[]>('choices')
  const answers = defineModel<Answer[]>('answers')
  const questionnaireId = defineModel<number>('questionnaireId')
  const choice = ref<Option>(new Option({id: 0,questionnaire_id: 0,label: 'お選びください', value:0}))
  const initial: Option = new Option({id: 0,questionnaire_id: 0,label: 'お選びください', value:0})

  watch(() => choice.value, (newValue) => {
    choice.value = newValue
    if (choices.value !== undefined && answers.value !== undefined) {
      const existingIndex = choices.value.findIndex(choice => choice.questionnaireId === newValue.questionnaireId)
      if (existingIndex !== -1) {
        choices.value.splice(existingIndex, 1, newValue)
        answers.value.splice(existingIndex, 1, Answer.fromData(0, newValue.questionnaireId, props.userId, newValue.id, null))
      } else {
        choices.value.push(newValue)
        answers.value.push(Answer.fromData(0, newValue.questionnaireId, props.userId, newValue.id, null))
      }
    }
  })
</script>

このコンポーネントを画面で使いたい。なんかVueってコンポーネント間での値の引き渡しとかやりづらいなあ・・・
アンケートのtypeによってコンポーネントを出し分けている。
画面から必要な変数を渡してあげている。

<template>
  <div class="container">
    <template v-for="respond in responds" :key="respond.id">
      <div>
        <table cellspacing="0">
          <tbody>
            <tr>
              <th colspan="2">アンケート</th>
            </tr>
            <template v-for="questionnaire in questionnaires" :key="questionnaire.id">
              <tr v-if="questionnaire.type">
                <th>{{ questionnaire.content }}</th>
                <td>
                  <div v-if="questionnaire.type === 1">
                    <check-component v-model:options="questionnaire.choices" v-model:questionnaire-id="questionnaire.id"
                      v-model:choices="respond.choices" v-model:answers="respond.answers"
                      :userId="respond.user.id"></check-component>
                  </div>
                  <div v-if="questionnaire.type === 2">
                    <radio-component v-model:options="questionnaire.choices" v-model:questionnaire-id="questionnaire.id"
                      v-model:choices="respond.choices" v-model:answers="respond.answers"
                      :userId="respond.user.id"></radio-component>
                  </div>
                  <div v-if="questionnaire.type === 3">
                    <select-component v-model:options="questionnaire.choices" v-model:questionnaire-id="questionnaire.id"
                      v-model:choices="respond.choices" v-model:answers="respond.answers"
                      :userId="respond.user.id"></select-component>
                  </div>
                  <div v-if="questionnaire.type === 4">
                    <text-component v-model:options="questionnaire.choices" v-model:questionnaire-id="questionnaire.id"
                      v-model:choices="respond.choices" v-model:answers="respond.answers"
                      :userId="respond.user.id"></text-component>
                  </div>
                </td>
              </tr>
            </template>
          </tbody>
        </table>
      </div>
    </template>
  </div>
</template>

<script setup lang="ts">
  import { computed, onMounted, ref, watch } from 'vue'
  import { useRoute, useRouter } from 'vue-router'
  import SelectComponent from '@/components/SelectComponent.vue'
  import RadioComponent from '@/components/RadioComponent.vue'
  import TextComponent from '@/components/TextComponent.vue'
  import CheckComponent from '@/components/CheckComponent.vue'
  import { Respond } from '@/questionnaire'

  const responds = ref<Respond[]>([])
</script>

setup構文って最初書きづらかったが割と好きになってきた!

コメント

タイトルとURLをコピーしました