【Vue.js3】ボタンクリックで入力フォームを動的に追加する

ボタンクリックなどで動的に入力フォームを追加する方法を
実装するたびにやり方を忘れるので備忘録で残しておきます。※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>

コメントを残す

入力エリアすべてが必須項目です。メールアドレスが公開されることはありません。

内容をご確認の上、送信してください。