Vue のバリデーションライブラリの一つである VeeValidate を使うと動的なバリデーションチェックが行われるフォームを低コストで実装することができます。通常はクライアント側で持っているデータやロジックに基づいたバリデーションを行いますが、 Web API など非同期的な処理を挟んだ動的なバリデーションチェックを実装する機会があったので、その方法をメモします。
なお API client の実装自体は本題から逸れるので割愛します。
TL;DR
- ValidateProvider の applyResult を利用すればバリデーションエラーをマニュアル追加できる。
環境
- Vue: 2.x
- Composition API を使用
- VeeValidate: 3.2.5
- TypeScript: 3.7.4
実装
シチュエーションとしてはホテルや旅客機などの予約日を入力するフォームを想定しています。
以下のコードでは日付のフォーマットなどをフロントエンドのみでバリデーションチェックし、指定した日付が予約可能かのチェックでサーバへの問い合わせを行います。
<template>
<ValidationProvider
v-slot="{ errors }"
ref="provider"
name="予約日"
rules="required|'date_format:dd/MM/yyyy'"
>
<input
v-model="value"
type="text"
@blur="checkRegistrable"
/>
<span>{{ errors[0] }}</span>
</ValidationProvider>
</template>
<script lang="ts">
import { createComponent, ref, watch } from '@vue/composition-api'
import { ValidationResult } from 'vee-validate/dist/types/types'
import { useReservationDate } from '~/compositions/reservation-date'
export default createComponent({
setup() {
const { checkIfRegistrable } = useReservationDate()
const value = ref<string | null>(null)
const checkRegistrable = async () => {
const result: ValidationResult = await provider.value.validate()
if (!result.valid) {
return
}
const canRegister: boolean = await checkIfRegistrable(val.value)
if (!canRegister) {
provider.value.applyResult({
errors: ['この日付は指定できません。'],
valid: false,
failedRules: {}
})
}
}
return {
value,
provider
}
}
})
</script>
<input>
タグで blur イベントが発生した際に checkRegistrable
というメソッドが実行されます。
メソッド内部ではまず通常のバリデーションチェックを行い、結果が valid だった場合は予約日に関するロジックを集約した composition の useReservationDate
から checkIfRegistrable
を呼び出します。ここで checkIfRegistrable
は API の呼び出し結果を boolean で返すようなメソッドとなる想定です。
この結果が false の場合は ValidateProvider の applyResult というメソッドを利用してバリデーションの状態を invalid に変更します。