Open5

Yup小技集

hoshitahoshita

numberもしくはnullかをチェックしたい場合

https://tech.motoki-watanabe.net/entry/2021/01/23/205510

ts
yup
.number()
.nullable()
.transform((value, originalValue) =>
  String(originalValue).trim() === '' ? null : value
)

これでチェックのところは解決したが、String型で出力されてしまう。

本来は上記の処理で組み込みたかったが一旦スキップ。

暫定的にsubmitする直前にNumber()で数値型にする

hoshitahoshita

特定のいずれかにチェックが入っていることを確認する

const validationSchema = Yup.object().shape({
  online: Yup.boolean(),
  offline: Yup.boolean(),
  hybrid: Yup.boolean(),
  // カスタムバリデーションで少なくとも1つが true か確認
}).test('at-least-one-true', 'オンライン、オフライン、またはハイブリッドのいずれかを選択してください', function (values) {
  const { online, offline, hybrid } = values;
  return online || offline || hybrid;
});

testを使用することで実現可能

hoshitahoshita

数字を指定し、その数だけ値が入力されているか確認

    examNum: Yup.number().required('試験回数を入力してください').min(1, '1以上の数を入力してください'),
    examDate: Yup.array()
      .of(Yup.date().required('開催予定日を入力してください'))
      .test('check-examNum', 'すべての試験予定日を入力してください', function (value) {
        const { examNum } = this.parent;
        return value && value.length >= examNum && value.slice(0, examNum).every((date) => date !== null);
      }),

examNum

examNumでは1以上の数値が入っているかを確認する
number()で数値であること、requiredで必須項目として定義する

examDate

examDateはそれぞれの日付が入力されているかを確認する。

配列の中身を定義する方法は上記のarray().of(yup.number())もしくはarray(yup.number());の2種類がある。 公式ドキュメント-array

その後、testを使用して作成した入力欄に記入されているかを確認する
test()の第一引数はテスト名、第二引数が失敗した際に表示するエラーメッセージ

this.parent は、examDate が属しているオブジェクト全体を参照する。parent経由で他の値を参照することができる

functionの引数にはexamDateの値が格納される

value && value.length >= examNumでexamDate 配列の長さが examNum 以上であることを確認。

value.slice(0, examNum).every((date) => date !== null)value.slice(0, examNum) は、examDate 配列の最初から examNum 個までの要素を抽出

.every((date) => date !== null) は、抽出した要素がすべて null ではないことを確認します。つまり、必要な試験日すべてが入力されていることを検証 (everyについて)

hoshitahoshita

AutoCompleteのエラー対応

The value provided to Autocomplete is invalid.
None of the options match with `{"id":1,"name":"Instructor 1"}`.
You can use the `isOptionEqualToValue` prop to customize the equality test. Error Component Stack

上記のエラーに対してはエラーメッセージ通りisOptionEqualToValueを追加することで解消

    <Autocomplete
     // 省略
      isOptionEqualToValue={(option: Instructor, value: Instructor) => option.id === value.id}
      // 省略
    />```
hoshitahoshita

動的なバリデーション

配列で回して作成したインプットフォームのバリデーションルール

const attendanceSchemas = attendance.reduce((acc, item) => {
  const methodField = `method${item.method}`;
  const attendanceField = `${methodField}Attendance`;

  return {
    ...acc,
    [attendanceField]: Yup.number()
      .typeError('人数は数値で入力してください')
      .nullable()
      .transform((value, originalValue) => (String(originalValue).trim() === '' ? null : value))
      .when(methodField, {
        is: true,
        then: (schema) =>
          schema
            .required('人数は必須です')
            .min(1, '1以上の数を入力してください')
            .max(9999, '9999以下の数を入力してください'),
      }),
  };
}, {});

const validationSchema = Yup.object()
  .shape(
    {
      // 省略
      ...attendanceSchemas,
    },
    [],
  )