1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Vue.js】yupを使用して配列項目を条件によってチェック内容を変えたい

Posted at

概要

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>
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?