【Vue.js】セレクトボックス変更時にフォームの入力値データをリセットする方法

  • URLをコピーしました!

この記事ではVue.jsを使ってセレクトボックスの選択項目を変更した時にフォームの入力値データをリセットする方法をまとめます。

初心者向けの記事です。

Vue.jsを使いこなせるレベルの方は勉強にならないと思いますm(__)m

CSSを当てていないのでとてもシンプルな見た目ですが、このような画面を作成します。

ケースとしては1つの条件で行う検索機能を考えます。

仕様は以下の通りとします。

  • 検索条件のセレクトボックスで選択・変更できる(例として名前、年齢)
  • セレクトボックスで選択したそれぞれの項目用の入力フォームを設けて、セレクトボックスの選択項目の変更によって表示するフォームを切り替える
  • セレクトボックスの選択項目を変更した場合はフォームの入力値をリセットする
  • 「入力値」のところに各フォームの入力値を表示する

ということで実装しながら解説していきます。

セレクトボックスで選択した項目それぞれ用の入力フォームを設けてプルダウンの変更によって表示するフォームを切り替える方法(上記リストの2番目まで)に関してはこちらの記事で実装しているので実装方法がイメージできない方はこちらの記事をご覧ください。

オススメ教材

目次

使うVue.jsの機能

  • v-forディレクティブ
  • v-if ディレクティブ
  • v-bindディレクティブ
  • v-modelディレクティブ
  • データ(data)
  • 算出プロパティ(computed)
  • ウォッチャ(watch)

完成版コード

<template>
  <div id="app">
    <h2>検索条件</h2>
    <select v-model="selectedItem">
      <option v-for="item in itemLists" :value="item.id" :key="item.id">
        {{ item.label }}
      </option>
    </select>
    <div v-if="isNameForm">
      名前:<input v-model="name" type="text" />
    </div>
    <div v-if="isAgeForm">
      年齢:<input v-model="age" type="text" />
    </div>
    <div>
      <button type="submit">submit</button>
    </div>
    <p>入力値(名前):{{ name }}</p>
    <p>入力値(年齢):{{ age }}</p>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      itemLists: [
        { id: 1, label: "名前" },
        { id: 2, label: "年齢" },
      ],
      selectedItem: 1,
      name: "",
      age: "",
    };
  },
  computed: {
    isNameForm() {
      return this.selectedItem === 1;
    },
    isAgeForm() {
      return this.selectedItem === 2;
    },
  },
  watch: {
    selectedItem(value) {
      if (value === 2) {
        this.name = "";
      }
      if (value === 1) {
        this.age = "";
      }
    },
  },
};
</script>

実装手順

実装手順としては以下の通りです。

  • セレクトボックスの作成
  • 入力フォームの作成
  • 選択項目、入力フォームのデータを定義
  • セレクトボックスの選択による入力フォームの表示切り替え
  • セレクトボックスの選択項目を変更した時にフォームの入力値データをリセットする

ということで1つずつ解説していきます。

セレクトボックスの作成

まずはセレクトボックスを作成します。

セレクトボックスの選択肢は「名前」と「年齢」とするので、dataプロパティに定義して、テンプレート内で表示します。

以下のコードで実装します。

<select v-model="selectedItem">
  <option v-for="item in itemLists" :value="item.id" :key="item.id">
    {{ item.label }}
  </option>
</select>
  data() {
    return {
      itemLists: [
        { id: 1, label: "名前" },
        { id: 2, label: "年齢" },
      ],
    };
  },

入力フォームの作成

入力フォームの作成はVue.jsの内容ではないので簡単ですね。

<div>
  名前:<input type="text" />
</div>
<div>
  年齢:<input type="text" />
</div>
<div>
  <button type="submit">submit</button>
</div>

この記事で実装する仕様ではボタンは不要ですが、それっぽく見せるために一応つけています。

選択項目、入力フォームのデータを定義

次に

  • セレクトボックスで現在選択している項目がどちらかを保持するデータ
  • 入力フォームで入力したデータを保持するデータ

を定義します。

data() {
    return {
      // 略
      selectedItem: 1,
      name: "",
      age: "",
    };
  },

定義したdataプロパティは以下の通り。

  • selectedItem:セレクトボックスで現在選択している項目
  • name:名前用の入力フォームに入力されている値
  • age:年齢用の入力フォームに入力されている値

dataプロパティとセレクトボックス、入力フォームの値をそれぞれ双方向データバインディングさせます。

    <select v-model="selectedItem">
      <option v-for="item in itemLists" :value="item.id" :key="item.id">
        {{ item.label }}
      </option>
    </select>
    <div>
      名前:<input v-model="name" type="text" />
    </div>
    <div>
      年齢:<input v-model="age" type="text" />
    </div>
  • selectタグにv-model="selectedItem"を追加
  • inputタグにv-model="name"v-model="age"を追加

双方向データバインディングはv-modelディレクティブを使います。

v-model=""のダブルクオーテーションの中にはdataプロパティを書きます。

こうすることでセレクトボックスの選択項目変更、入力フォームへの値の入力に連動してリアルタイムにdataプロパティが反映されます。

超便利です。Vue.jsの大きな機能の1つですね。

あとはついでですが、dataプロパティのnameとageの値を表示させておきます。
(実際にリアルタイムでdataプロパティが入力フォームと連動して変化している様子を見やすくするため)

<p>入力値(名前):{{ name }}</p>
<p>入力値(年齢):{{ age }}</p>

ここまで実装が終わった時点で入力フォームで適当に何か入力すると上記で実装したpタグに入力した値が表示され、それがリアルタイムで変更されます。(これが双方向データバインディング)

セレクトボックスの選択による入力フォームの表示切り替え

次に、セレクトボックスの選択によって名前用と年齢用の入力フォームの表示を切り替えます。

これは過去の記事で解説しているので説明は割愛しますが、以下の部分です。

<template>
  <div id="app">
    <!-- 略 -->
    <div v-if="isNameForm">
      名前:<input v-model="name" type="text" />
    </div>
    <div v-if="isAgeForm">
      年齢:<input v-model="age" type="text" />
    </div>
    <!-- 略 -->
  </div>
</template>

<script>
export default {
  // 略
  computed: {
    isNameForm() {
      return this.selectedItem === 1;
    },
    isAgeForm() {
      return this.selectedItem === 2;
    },
  },
 // 略
};
</script>

詳しく知りたい方はこちらをご覧ください。

ここまで終わると、セレクトボックスで「名前」を選択したときは「名前:入力フォーム」、「年齢」を選択したときは「年齢:入力フォーム」と表示が切り替わります。

セレクトボックスの選択項目を変更した時にフォームの入力値データをリセットする

ここまででだいぶ形になりましたが最後の仕上げです。

今の問題点としては、

名前の入力フォームに何か入力した後にセレクトボックスを年齢に変えると、名前の入力フォームに入力した文字列が残ってしまっている

ことです。

これ、何が問題かというと、今回のケースだと、”名前と年齢”のような複数条件の検索は想定しておらず、セレクトボックスで選択した項目のみに値を持たせたいのですが、今のままだと上記の問題が発生します。
(思わぬパラメータが送信されてしまうという意味です)

これを解決するためにはウォッチャ(watch)という機能を使います。

ウォッチャはある値を監視して、値が変更されるたびに処理を実行するためのものです。

ウォッチャを追加したコードがこちらです。完成形と同じです。

<template>
  <div id="app">
    <h2>検索条件</h2>
    <select v-model="selectedItem">
      <option v-for="item in itemLists" :value="item.id" :key="item.id">
        {{ item.label }}
      </option>
    </select>
    <div v-if="isNameForm">
      名前:<input v-model="name" type="text" />
    </div>
    <div v-if="isAgeForm">
      年齢:<input v-model="age" type="text" />
    </div>
    <div>
      <button type="submit">submit</button>
    </div>
    <p>入力値(名前):{{ name }}</p>
    <p>入力値(年齢):{{ age }}</p>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      itemLists: [
        { id: 1, label: "名前" },
        { id: 2, label: "年齢" },
      ],
      selectedItem: 1,
      name: "",
      age: "",
    };
  },
  computed: {
    isNameForm() {
      return this.selectedItem === 1;
    },
    isAgeForm() {
      return this.selectedItem === 2;
    },
  },
  // ウォッチャ定義
  watch: {
    selectedItem(value) {
      if (value === 2) {
        this.name = "";
      }
      if (value === 1) {
        this.age = "";
      }
    },
  },
};
</script>

ウォッチャはこのように定義しました。

  watch: {
    selectedItem(value) {
      if (value === 2) {
        this.name = "";
      }
      if (value === 1) {
        this.age = "";
      }
    },

処理を細分化します。

  • dataのselectedItemを監視する(=セレクトボックスの選択項目を監視する)
  • selectedItemが変更すると{ }内の処理が実行される
  • 引数valueにはselectedItemの値が入る
  • valueが2(=年齢)の時、dataのnameを空にする
  • valueが1(=名前)の時、dataのageを空にする

今回は簡略化のため、1、2という数字をベタ書きしていますが、これはマジックナンバーなので本来は定数等を定義してパッと見て意味がわかるようにすべきです。(マジックナンバーはご法度です)

マジックナンバーって何?という方はこちらをご覧ください。

これでセレクトボックスの選択肢を変更した場合に、入力フォームの値をクリアすることができました。

他の実装パターンもご紹介しておきます。

追加パターン1

セレクトボックスを選択した段階で両方の入力フォームの値を空にする処理です。

正直先ほどの処理よりこっちの方がスッキリして良いですね。

  watch: {
    selectedItem(value) {
      this.name = "";
      this.age = "";
    },
  },

追加パターン2

初めにご紹介したパターンと似ていますが、監視対象をselectedItem(選択項目)ではなく、算出プロパティ(computed)のisNameFormisAgeFormにしています。

それぞれ、trueの時に入力フォームの値を空にしています。

  watch: {
    isNameForm(value) {
      if (value) {
        this.age = "";
      }
    },
    isAgeForm(value) {
      if (value) {
        this.name = "";
      }
    }
  },

このように1つの仕様を実装する方法がいくつもあるのは面白いですが、難しいところですね…

何はともあれ、完成です。

最後に

Vue.jsを使ってセレクトボックスの選択項目を変更した時にフォームの入力値データをリセットする方法を解説しました。

おさらいのために最後にもう一度完成形のコードを載せておきます。

<template>
  <div id="app">
    <h2>検索条件</h2>
    <select v-model="selectedItem">
      <option v-for="item in itemLists" :value="item.id" :key="item.id">
        {{ item.label }}
      </option>
    </select>
    <div v-if="isNameForm">
      名前:<input v-model="name" type="text" />
    </div>
    <div v-if="isAgeForm">
      年齢:<input v-model="age" type="text" />
    </div>
    <div>
      <button type="submit">submit</button>
    </div>
    <p>入力値(名前):{{ name }}</p>
    <p>入力値(年齢):{{ age }}</p>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      itemLists: [
        { id: 1, label: "名前" },
        { id: 2, label: "年齢" },
      ],
      selectedItem: 1,
      name: "",
      age: "",
    };
  },
  computed: {
    isNameForm() {
      return this.selectedItem === 1;
    },
    isAgeForm() {
      return this.selectedItem === 2;
    },
  },
  // ウォッチャ定義
  watch: {
    selectedItem(value) {
      if (value === 2) {
        this.name = "";
      }
      if (value === 1) {
        this.age = "";
      }
    },
  },
};
</script>

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

ブログを開設するなら「SWELL」が絶対オススメ!

コメント

コメントする

目次