Nuxt.js+Vuetifyで、アカウント登録画面を実装しました。
フロントで最低限の入力チェックが通ったら、送信ボタンを押せるようにして、無駄なAPIリクエスト減らす。APIからの入力エラーもvee-validateを使用して、各項目に表示するようにしました。
合わせて、前回実装したログイン画面にも導入しました。
Nuxt.jsとRailsアプリのDevise Token Authを連携させて認証する

参考: フォーム・コンポーネント — Vuetify

初期表示

フロントの入力エラー

APIからの入力エラー

API通信エラー

vee-validate追加

$ yarn add vee-validate

アカウント登録画面

pages/users/sign_up.vue を作成

<template>
  <validation-observer v-slot="{ invalid }" ref="observer">

v-slotのinvalid: 下のv-btnのdisabledで使用。ボタンを押せるか否か。
refのobserver: 下のthis.$refs.observer.setErrorsで使用。

    <Message :alert="alert" :notice="notice" />

自作components → https://dev.azure.com/nightonly/nuxt-app-origin/_git/nuxt-app-origin/commit/8d6b7cb6c61470697cc9b5bc4a479aaa84e8b3a2

    <v-card max-width="480px">
      <v-form>
        <v-card-title>
          アカウント登録
        </v-card-title>
        <v-card-text>
          <validation-provider v-slot="{ errors }" name="name" rules="required">
            <v-text-field
              v-model="name"
              label="氏名"
              prepend-icon="mdi-account"
              :error-messages="errors"
            />
          </validation-provider>

v-slotのerrors: error-messagesに渡されて、表示される。
rules: 入力チェック(validate)内容。

          <validation-provider v-slot="{ errors }" name="email" rules="required|email">
            <v-text-field
              v-model="email"
              label="メールアドレス"
              prepend-icon="mdi-email"
              :error-messages="errors"
            />
          </validation-provider>
          <validation-provider v-slot="{ errors }" name="password" rules="required|min:8">
            <v-text-field
              v-model="password"
              type="password"
              label="パスワード [8文字以上]"
              prepend-icon="mdi-lock"
              append-icon="mdi-eye-off"
              :error-messages="errors"
            />
          </validation-provider>
          <validation-provider v-slot="{ errors }" name="password_confirmation" rules="required|confirmed:password">
            <v-text-field
              v-model="password_confirmation"
              type="password"
              label="パスワード(確認)"
              prepend-icon="mdi-lock"
              append-icon="mdi-eye-off"
              :error-messages="errors"
            />
          </validation-provider>
          <v-btn color="primary" :disabled="invalid" @click="signUp">
            登録
          </v-btn>
        </v-card-text>
        <v-card-actions>
          <ul>
            <li>
              <NuxtLink to="/users/sign_in">
                ログイン
              </NuxtLink>
            </li>
          </ul>
        </v-card-actions>
      </v-form>
    </v-card>
  </validation-observer>
</template>

<script>
import { required, email, min, confirmed } from 'vee-validate/dist/rules'
import { extend, ValidationObserver, ValidationProvider, setInteractionMode } from 'vee-validate'
import Message from '~/components/Message.vue'

setInteractionMode('eager')

eager(デフォルト)かlazy
> フォーカスアウト時にバリデーションが走り、エラーの場合は、エラーが消えるまで入力中でも、バリデーションが走る
VeeValidateのバリデーション発火タイミングを変更する方法 | ガクLog

extend('required', {
  ...required,
  message: '入力してください。'

TODO: vee-validateのlocale使うか、vue-i18nを使った方が良さそう。
publicRuntimeConfigで環境毎の値を保持とi18n対応

})
extend('email', {
  ...email,
  message: '形式が正しくありません。'
})
extend('min', {
  ...min,
  message: '{length}文字以上で入力してください。'
})
extend('confirmed', {
  ...confirmed,
  message: 'パスワードと一致しません。'
})

export default {
  name: 'UsersSignUp',

> nameプロパティをつける理由は、(1)処理の中でそのデータ(値)を使うから。
> あるいは、(2)デバッグ用として。
【Vue】export defaultのnameについて – Qiita

  components: {
    ValidationObserver,
    ValidationProvider,
    Message
  },

  data () {
    return {
      alert: null,
      notice: null,
      name: '',
      email: '',
      password: '',
      password_confirmation: ''
    }
  },

  created () {
    if (this.$auth.loggedIn) {
      this.$toasted.info('既にログインしています。')
      return this.$router.push({ path: '/' })
    }

「middleware: ‘auth’」でも出来ますが、メッセージ出す為。
toast便利ですね。下記で追加。

$ yarn add @nuxtjs/toast
  },

  methods: {
    async signUp () {
      await this.$axios.post('http://localhost:3000/users/auth/sign_up.json', {

TODO: URLは環境毎に変わるので、cross-envを使った方が良さそう。
publicRuntimeConfigで環境毎の値を保持とi18n対応

        name: this.name,
        email: this.email,
        password: this.password,
        password_confirmation: this.password_confirmation,
        confirm_success_url: 'http://localhost:5000/users/sign_in'
      })
        .then((response) => {
          return this.$router.push({ path: '/users/sign_in', query: { alert: response.data.alert, notice: response.data.notice } })

成功時は、パラメータでメッセージ渡して、ログイン画面で表示して貰う。

        },
        (error) => {
          if (error.response == null) {

前回は、(typeof error.response === ‘undefined’)を使っていたけど、これに変更。
===(3つ)にするとfalseになるので、==(2つ)

            this.$toasted.error('通信に失敗しました。しばらく時間をあけてから、やり直してください。')
          } else {
            this.alert = error.response.data.alert
            this.notice = error.response.data.notice
            this.$refs.observer.setErrors(error.response.data.errors)

APIからの入力エラーをsetErrorsで渡してあげるだけで表示される。
observer: 上のvalidation-observerのrefで定義。

          }
          return error
        })
    }
  }
}
</script>

ログイン画面

初期表示

フロントの入力エラー

APIからの入力エラー

認証成功


今回のコミット内容
https://dev.azure.com/nightonly/nuxt-app-origin/_git/nuxt-app-origin/commit/a9264e5b97c05bca850fb83b612363665aecd8a3

vee-validateで入力チェックした上で、APIからの入力エラーも各項目に表示する” に対して1件のコメントがあります。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です