ボタンクリックなどで動的に入力フォームを追加する方法を
実装するたびにやり方を忘れるので備忘録で残しておきます。※Vue.js 3.2
方法
動的フォームを作成する際、フォームの中に入ってくるデータのフォーマットは次のようなオブジェクトであることが多いと思います。
[
{ "id": 1, "title": "タイトル1", "name": "太郎" },
{ "id": 2, "title": "タイトル2", "name": "次郎" }
]
なので入力されたデータが入るプロパティの初期値は空の配列にします。
const forms = ref([]);
追加
追加ボタンを押した際は、保存したいフォーマットと同じデータを生成します。
最後の一文、formsの後ろにvalueがついていますが、これはVue3系から登場した書き方で
ref で定義した値にアクセスするためには value というプロパティにアクセスする必要があるためです。
const addForm = () => { //追加ボタンをクリックしたときのイベント
let form_body = {};
form_body = {
title: "",
name: "",
};
forms.value.push(form_body);
};
削除
削除はv-forでループした配列のindex値を返してspliceによって削除しています。
const deleteForm = (index) => { //削除ボタンをクリックしたときのイベント
forms.value.splice(index, 1);
};
script部分
<script setup>
import { ref } from "vue";
const forms = ref([]); //入力されたデータが入るところ
const addForm = () => { //追加ボタンをクリックしたときのイベント
let form_body = {};
form_body = {
title: "",
name: "",
};
forms.value.push(form_body);
};
const deleteForm = (index) => { //削除ボタンをクリックしたときのイベント
forms.value.splice(index, 1);
};
</script>
template部分
先ほど定義したformsをv-forによってループさせています。
今回はオブジェクトのデータなのでエラーが出ませんが、文字列の配列をv-forでループさせ、取得した値をv-modelで定義すると以下のようなエラーを吐きます。
You are binding v-model directly to a v-for iteration alias. This will not be able to modify the v-for source array because writing to the alias is like modifying a function local variable. Consider using an array of objects and use v-model on an object property instead.
なのでをv-modelは以下のようにindexを使用して元の配列の要素を直接参照するように書きます。
v-model="forms[index].title"
<template>
<div>
<div class="row mb-2">
<div class="mr-2">
<button class="btn btn-sm btn-outline-success" @click="addForm()">
追加
</button>
</div>
</div>
<div v-for="(form, index) in forms" :key="index">
<div class="row">
<input
type="text"
name="title"
placeholder="タイトル"
v-model="forms[index].title"
/>
<input
type="text"
name="name"
placeholder="名前"
v-model="forms[index].name"
/>
<button class="btn btn-outline-danger" @click="deleteForm(index)">
×
</button>
</div>
</div>
</div>
</template>