概要
yupはcompositionAPIでyupとvee-validateを使ったバリデーションをするの記事にある通り、バリデーションルールを宣言的に記述することのできるライブラリです。項目毎のチェック内容について、ソースコードの見通しがけっこう良くなるので、使用感は悪くないライブラリと思います。
今回yupを使用し配列項目に対して、条件によってチェック内容を変えるVueの実装を紹介します。
実装方針
Reactの記事ではありますが、react-hook-form(yup)を使った重複チェックバリデーションにある通り、個別にバリデーションロジックを作成します。今回はこのバリデーションロジックの中で条件判定を行い、配列の項目毎にチェック内容を変えます。
実装サンプルの前提
- Vue3を前提とします。
- vee-validate4を併せて使用します。
- サンプルでは、以下のようにファイルの登録を可変で管理するものを、実装します。
<template>
<v-btn
class="ml-2 mb-1"
icon
width="20"
height="20"
color="indigo"
@click="pushFileExec"
>
<v-icon>mdi-plus</v-icon>
</v-btn>
<fieldset v-for="(fileField, idx) in fileFields" :key="idx">
<br />
<ErrorMessage :name="`referenceFiles[${idx}].fileName`" class="error" />
<Field
:id="`fileName_${idx}.fileName.id`"
:name="`referenceFiles[${idx}].fileName`"
style="width: 270px"
v-slot="{ field }"
>
<v-text-field
v-bind="field"
label="ファイル名"
style="width: 270px"
v-model="fileField.value.fileName"
></v-text-field>
</Field>
<ErrorMessage :name="`referenceFiles[${idx}].file`" class="error" />
<Field
:id="`file_${idx}.file.id`"
:name="`referenceFiles[${idx}].file`"
v-slot="{ handleChange }"
>
<input type="file" style="width: 270px" @change="handleChange" />
</Field>
<!-- ここは値保持のためなので非表示で設定 -->
<span v-show="false">
<Field
:id="`referenceFiles_${idx}`"
:name="`referenceFiles[${idx}].registeredId`"
></Field>
</span>
<br />
<br />
<v-btn
class="ml-2 mb-1"
icon
width="20"
height="20"
color="indigo"
@click="
() => {
removeFileExec(idx);
}
"
>
<v-icon>mdi-minus</v-icon>
</v-btn>
</fieldset>
</template>
<script>
import { defineComponent } from "vue";
import { useFieldArray, useForm, ErrorMessage, Field } from "vee-validate";
import * as yup from "yup";
export default defineComponent({
components: {
ErrorMessage,
Field,
},
setup() {
const {
remove: removeFile,
push: pushFile,
fields: fileFields,
update: updateFile,
replace: replaceFile,
} = useFieldArray("referenceFiles");
const pushFileExec = () => {
pushFile({
fileName: "",
file: undefined,
registeredId: undefined,
});
};
const removeFileExec = (idx) => {
removeFile(idx);
};
return {
fileFields,
pushFileExec,
removeFileExec,
};
},
});
</script>
チェック部分の実装サンプル
条件として上記の前提に記載している、配列内のオブジェクトにあるregisteredId
の項目が未設定の場合、file
の登録を必須にするというのを実装してみます。
以下がバリデーション部分の実装です。
<script>
// バリデーションロジックの定義
function validateFileUpload(file) {
// チェック対象が「file」項目だが、条件判定のため親のオブジェクトをこれで取得する。
const referenceFile = this.from[0].value;
// IDが既に登録されている場合は無条件でOK
if (referenceFile.registeredId) {
return true;
} else {
// IDが登録されていない場合はfileの登録を必須
if (file && file.length > 0) {
return true;
}
return false;
}
}
// 入力フォームの設定
const postRegisterSchema = yup.object({
referenceFiles: yup
.array()
.of(
yup.object().shape({
file: yup
.array()
.test(
"file-upload-check",
"ファイルを登録してください",
validateFileUpload // バリデーションロジック
),
})
).strict(),
});
const formContext = useForm({
validationSchema: postRegisterSchema,
});
</script>