🚀

【Vuetify 3】ログイン画面にバリデーションを追加

2023/06/18に公開

目標

サインイン/サインアップ画面にバリデーション処理を追加する

  • バリデーションルールの追加
  • 各入力情報を送信処理の前にバリデーションを適応させる

事前準備

vue3に事前準備uetify3が導入されたProject
記事では下記Git hub Repositoryを使用する
https://github.com/viviomega/vue-viviomega

Vuelidate2の導入

https://vuelidate-next.netlify.app/
バリデーション用のパッケージの導入
Vuelidate2になって使用感がすごく変わっているので学習コストがかかる気がしてます

yarn add @vuelidate/core @vuelidate/validators

必要なライブラリのインポート

src/LoginView.vue
-import { ref, onMounted } from "vue";
+import { ref, reactive, onMounted } from "vue";
 
+import { useVuelidate } from "@vuelidate/core";
+import { email, required, minLength } from "@vuelidate/validators";

バリデーションの設定

Vuelidateの実装方法を参考
https://vuetifyjs.com/en/components/forms/#vuelidate

サインイン/サインアップにバリデーションを追加していきます
パスワードのバリデーションは今回最低限にします

バリデーション内容
email 必須 メールアドレスのフォーマット
password 必須 最小8文字

入力項目のデータを変更

src/LoginView.vue
+const state = reactive({
+  email: "",
+  password: "",
+});
 
-const email = ref("");
-const password = ref("");

入力項目をオブジェクトで管理する事になるので単体で呼び出していた各所をオブジェクトととして呼び出す記述に変更する必要がある

+state.emial
-email
-email.value

ルールを設定したオブジェクトを追加

src/LoginView.vue
+// バリデーションルール
+const rules = {
+  email: { required, email },
+  password: { required, minLengthValue: minLength(8) },
+};

入力項目にバリデーションの適応

src/LoginView.vue
+// モデルにバリデーションを適応
+const v$ = useVuelidate(rules, state)

v-text-fieldにも項目を追加

イベントハンドラ 概要
@input 入力がされた際にイベントが発火
@blur フォーカスが外れた際にイベントが発火
src/LoginView.vue
 <v-text-field
   v-model="state.email"
   :label="constant.email"
   type="email"
+  :error-messages="v$.email.$errors.map((e) => e.$message)"
+  @input="v$.email.$touch"
+  @blur="v$.email.$touch"
 >
 </v-text-field> 

パスワードの入力項目も同様に修正を行う

実行結果

ボタン押下を行った際にバリデーションチェック実行

サインイン/サインアップを実行した際にバリデーションチェックする
async/awaitで非同期させないとボタンを押下した際にバリデーションチェックを無視してレスポンスを行います

src/LoginView.vue
 // サインイン処理
-const signin = () => {
+const signin = async () => {
   // バリデーションエラー時は処理を停止
+  const isFormCorrect = await v$.value.$validate();
+  if (!isFormCorrect) return;
   ...
 };

 // サインアップ処理
-const createAccount = () => {
+const createAccount = async () => {
   // バリデーションエラー時は処理を停止
+  const isFormCorrect = await v$.value.$validate();
+  if (!isFormCorrect) return;
   ...
 };

実行結果

ボタンを押下際にメッセージが上手く表示されませんでした。
こちら調べたのですが原因がわかりませんでした。
エラー箇所は赤で表示されるので問題ないと思われますので今回はこのままにします

入力フォームのレイアウトバランス調整

入力フォームの下にエラーメッセージが表示された事で今までのレイアウトだと表示がギチギチになってしまう(エラーメッセージの領域を考慮していなかった自分のミス)ので幅を調整していきますが、スタイルやclassで設定すると、今後他の入力フォームでも同じような調整を求められ修正などに手間が発生するのでv-rowで全体を囲み各入力フォームにv-colを設定していくようにする

https://vuetifyjs.com/en/components/grids/#sub-components

src/LoginView.vue[修正前]
<v-col>
  <v-text-field
    v-model="state.email"
    :label="constant.email"
    type="email"
    :error-messages="v$.email.$errors.map((e) => e.$message)"
    @input="v$.email.$touch"
    @blur="v$.email.$touch"
  >
  </v-text-field>
  <v-text-field
    v-model="state.password"
    :label="constant.password"
    :type="show ? 'text' : 'password'"
    :append-inner-icon="show ? 'mdi-eye' : 'mdi-eye-off'"
    @click:append-inner="show = !show"
    :error-messages="v$.password.$errors.map((e) => e.$message)"
    @input="v$.password.$touch"
    @blur="v$.password.$touch"
  >
  </v-text-field>
  <v-btn color="primary" variant="tonal" @click="signin">
    {{ constant.signin }}
  </v-btn>
  <v-btn color="primary" variant="tonal" @click="createAccount">
    {{ constant.sinup }}
  </v-btn>
</v-col>
src/LoginView.vue[修正後]
<v-row>
  <v-col cols="12">
    <v-text-field
      v-model="state.email"
      :label="constant.email"
      type="email"
      :error-messages="v$.email.$errors.map((e) => e.$message)"
      @input="v$.email.$touch"
      @blur="v$.email.$touch"
    >
    </v-text-field>
  </v-col>
  <v-col cols="12">
    <v-text-field
      v-model="state.password"
      :label="constant.password"
      :type="show ? 'text' : 'password'"
      :append-inner-icon="show ? 'mdi-eye' : 'mdi-eye-off'"
      @click:append-inner="show = !show"
      :error-messages="v$.password.$errors.map((e) => e.$message)"
      @input="v$.password.$touch"
      @blur="v$.password.$touch"
    >
    </v-text-field>
  </v-col>
  <v-col cols="12">
    <v-btn color="primary" variant="tonal" @click="signin">
      {{ constant.signin }}
    </v-btn>
    <v-btn color="primary" variant="tonal" @click="createAccount">
      {{ constant.sinup }}
    </v-btn>
  </v-col>
</v-row>

Vuelidate2メリット

ビルトインがある事で必須項目やメールアドレスなど、自分で実装するにはバグを発生させたくない部分を確実に実装できる

Vuelidate2デメリット

テンプレートにイベントハンドラやエラーメッセージに値を渡してあげる処理を追加する必要がある
エラーメッセージを日本語に変更する処理が別途必要(現在未実装)

Git commit情報

今回の修正は量が多いので全体を確認したい場合はcommit履歴を確認しましょう

SHA commit message
9c48b82 【Vuetify 3】ログイン画面にバリデーションを追加

あとがき

別途メッセージの日本語化の記事を作成する
Vuelidateは2になってから使用感が大幅に変わった。
扱いにくくはなった気がするがビルトイン機能はすごく助かるので使わないわけにはいかない

Discussion