やりたいこと
一覧形式のフォームで、全データのバリデーション後に送信
この記事では、Vuetifyのv-data-tableを使って、一覧形式で表示されたユーザーの入力欄を持つフォームでデータ送信前に一括でバリデーションを行う方法を記載します。
今回は各ユーザーの「項目A(下限・上限)」と「項目B(下限・上限)」の各入力欄で「下限値が上限値より大きい」という矛盾が発生していないかをチェックし全ての入力のエラーが一切ない場合にのみデータを送信します。
一括バリデーションのメリット
- データの整合性: 送信前にまとめてエラーをチェックするので、サーバーに送るデータの整合性を保証できる。
- ユーザーの負担軽減: ユーザーはまとめてエラーを確認・修正できる。
- サーバー負荷の軽減: 不正なデータを含むリクエストを減らせるので、サーバーの負荷を減らせる。
実装のポイント:メソッドでバリデーションチェック
各入力欄の値(下限値と上限値)を取得し「下限値が上限値より大きい」というエラーがないか確認します。
エラーが見つかった場合は、エラーチェック用のオブジェクトに記録します。
コード全体
<template> <v-data-table :items="localItems" > // 入力欄 <template v-slot:item.itemA="{ item }"> <div> <v-text-field v-model.number="item.itemA.value1" :rules="itemRulesA[item.id] || []" @input="checkInput(item, 'itemA')" /> <div>〜</div> <v-text-field v-model.number="item.itemA.value2" :rules="itemRulesA[item.id] || []" @input="checkInput(item, 'itemA')" /> </div> </template> <template v-slot:item.itemB="{ item }"> <div> <v-text-field v-model.number="item.itemB.value1" :rules="itemRulesB[item.id] || []" @input="checkInput(item, 'itemB')" /> <div>〜</div> <v-text-field v-model.number="item.itemB.value2" :rules="itemRulesB[item.id] || []" @input="checkInput(item, 'itemB')" /> </div> </template> </v-data-table> </template> ------------------- <script> export default { data() { return { errorsObject: {}, // エラー情報を記録するオブジェクト localItems: [], // データテーブルのアイテム itemRulesA: {}, // 項目Aのルール(エラーメッセージ表示用) itemRulesB: {}, // 項目Bのルール(エラーメッセージ表示用) }; }, methods: { /** * 項目A・項目Bが[下限 > 上限]の場合のバリデーションチェック * @param {object} item - 各ユーザーのデータ * @param {string} itemHeadName - 入力した項目名('itemA' or 'itemB') */ checkInput(item: any, itemHeadName: string) { const lowerValue = Number(item[itemHeadName].value1); // 下限値 const upperValue = Number(item[itemHeadName].value2); // 上限値 // エラーオブジェクトの初期化(必要時のみ) this.errorsObject[item.id] = this.errorsObject[item.id] || {}; const error = lowerValue > upperValue; // エラーの有無とエラーメッセージを設定 this.errorsObject[item.id][itemHeadName] = error; if (itemHeadName === 'itemB') { this.itemRulesB[item.id] = error ? ['ルール:下限が上限を超えてはいけません'] : []; } else if (itemHeadName === 'itemA') { this.itemRulesA[item.id] = error ? ['ルール:下限が上限を超えてはいけません'] : []; } // 全てのエラーをチェックして問題なければ送信 if (!this.checkErrors()) { this.$emit('itemInput', this.localItems); } }, /** * 全てのユーザーの入力データにエラーが存在するかどうかを判定する * @returns {boolean} エラーが存在する場合はtrue、そうでない場合はfalse */ checkErrors() { return Object.values(this.errorsObject).some(rowErrors => Object.values(rowErrors).some(error => error) ); }, } }; </script>
コード解説
template:
v-data-table
:localItemsのデータを表示します。v-slot:item.itemA, v-slot:item.itemB
:「項目A」と「項目B」の列の表示内容を定義v-text-field
: テキストフィールドコンポーネント- v-model.number:number修飾子で数値として扱い、ユーザーの入力値をlocalItems内のデータと紐づけ。
- @input:項目に入力があるたびにcheckInputメソッドを呼び出す。
- :rules:エラーメッセージを表示するためのルールを設定します。
itemRulesAとitemRulesBからエラーがあればエラーメッセージを返します。
script:
-
data:
errorsObject
:エラー情報を記録するオブジェクト。ユーザーIDと項目名をキーにして、エラーがあるかどうか (true or false)を記録localItems
:データテーブルに表示するユーザーデータ。itemRulesA,
:エラーメッセージ表示用のルールを格納するオブジェクト。itemRulesB
ユーザーIDをキーにエラーメッセージを返す関数を配列を保持
-
methods:
-
checkInput
:
1. 入力された「下限値」と「上限値」を取得
2. エラー情報を記録するerrorsObjectを、必要に応じて初期化
3. 「下限値 > 上限値」ならエラーの判別でerrorsObjectにtrueを記録
4. エラーがあればitemRulesA または itemRulesBにエラーメッセージ表示用の関数を追加
5. checkErrorsメソッドを呼び出し、全てのエラーをチェックして問題なければ親コンポーネントに送信 -
checkErrors
:
1. errorsObjectをチェックして、エラーが記録されているかどうかを判定
2. エラーがあればtrueを返し、なければfalseを返す。
-
一覧フォームの入力バリデーションのポイント
- エラー情報をerrorsObjectに記録:エラーがあったら場合、errorsObjectに記録します。
// errorsObject の構造 { "user1のID": { "itemA": false, // 項目Aはエラー:なし "itemB": true // 項目Bはエラー:あり }, "user2のID": { "itemA": false, // 項目Aはエラー:なし "itemB": false // 項目Bはエラー:なし } }
- 全てのエラーをチェックして問題なければ送信:checkErrorsでエラーがないことを確認してから親コンポーネントにデータを送信します。
まとめ
この記事では一覧形式のフォームでバリデーションを行う方法 を解説いたしました。
この方法なら、複数の入力欄でも間違ったデータを送信することなくすべての入力欄をまとめて修正できるため、ユーザーフレンドリー且つデータの整合性も保証できると思います。ぜひ活用してみてください!