You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Formik+Yup表单验证:数组内对象关联验证规则实现求助

Hey there! Let's tackle those remaining validation rules one by one. I've adjusted your Yup schema to cover all 5 requirements, with comments explaining each part so you can follow along easily.

First, let's recap the rules we need to implement beyond the first one you already have:

  • Rule 2: If bookingDuration has items, every price in pricePerHours must be filled
  • Rule 3: If any price in pricePerHours is filled, bookingDuration must have at least one item
  • Rule 4: If maxGame is set (not empty/zero), every price in pricePerGame must be filled
  • Rule 5: If any price in pricePerGame is filled, maxGame must be set (and greater than zero)

Here's the updated Yup schema with all rules enforced:

const schema = Yup.object().shape({ 
  title: Yup.string() 
    .min(2, 'Must be 2 characters or more') 
    .required('Title is required'), 
  schedules: Yup.array().of( 
    Yup.object().shape({ 
      // Rule 1 + Rule 3: Booking Duration validation
      bookingDuration: Yup.array()
        // Rule 3: Require bookingDuration if any pricePerHours.price is filled
        .when('reservationSlots', {
          is: (reservationSlots) => {
            // Check if any pricePerHours entry has a non-empty, non-whitespace price
            return reservationSlots?.some(slot => 
              slot.pricePerHours?.some(pph => pph.price?.trim() !== '')
            );
          },
          then: Yup.array().min(1, 'Booking Duration is required when price per hour is set'),
          otherwise: Yup.array()
        })
        // Rule 1: Require bookingDuration if maxGame is empty/zero
        .when('maxGame', {
          is: (val) => val === '' || val === null || val === 0,
          then: Yup.array().min(1, 'Booking Duration is required'),
          otherwise: Yup.array()
        }),

      // Rule 1 + Rule 5: Max Game validation
      maxGame: Yup.number()
        // Rule 5: Require maxGame if any pricePerGame.price is filled
        .when('reservationSlots', {
          is: (reservationSlots) => {
            // Check if any pricePerGame entry has a non-empty, non-whitespace price
            return reservationSlots?.some(slot => 
              slot.pricePerGame?.some(ppg => ppg.price?.trim() !== '')
            );
          },
          then: Yup.number()
            .min(1, 'Max Game must be greater than zero when price per game is set')
            .required('Max Game is required when price per game is set'),
          otherwise: Yup.number()
        })
        // Rule 1: Require maxGame if bookingDuration is empty
        .when('bookingDuration', {
          is: (bookingDuration) => bookingDuration.length === 0,
          then: Yup.number()
            .min(1, 'Max Game must be greater than zero')
            .required('Max Game is required either fill booking duration'),
          otherwise: Yup.number()
        }),

      reservationSlots: Yup.array().of( 
        Yup.object().shape({ 
          from: Yup.date().typeError('Invalid Time'), 
          to: Yup.date().typeError('Invalid Time'), 
          increment: Yup.string().required('Time Increment is required'), 

          // Rule 2: Price Per Hours validation
          pricePerHours: Yup.array().of( 
            Yup.object().shape({ 
              guest: Yup.string(), 
              price: Yup.string()
                // Rule 2: Require price if bookingDuration has items
                .when('../../../bookingDuration', {
                  is: (bookingDuration) => bookingDuration?.length > 0,
                  then: Yup.string().required('Price is required when booking duration is set'),
                  otherwise: Yup.string()
                })
            }) 
          ), 

          // Rule 4: Price Per Game validation
          pricePerGame: Yup.array().of( 
            Yup.object().shape({ 
              type: Yup.string(), 
              price: Yup.string()
                // Rule 4: Require price if maxGame is set (non-empty/zero)
                .when('../../../maxGame', {
                  is: (maxGame) => maxGame !== null && maxGame !== '' && maxGame >= 1,
                  then: Yup.string().required('Price is required when max game is set'),
                  otherwise: Yup.string()
                })
            }) 
          ), 
        }) 
      ) 
    }, [['bookingDuration', 'maxGame']]) 
  ) 
});

Quick breakdown of key changes:

  1. Cross-level field access: We use ../../../ in the when clauses for price fields to reach up to the parent schedule object (since these price fields are nested 3 levels deep).
  2. Whitespace handling: Added trim() !== '' to ensure empty strings with whitespace are treated as invalid, making validation more robust.
  3. Optional chaining: Used ?. to avoid errors if nested arrays/objects are undefined (adds safety even if your form structure changes slightly).
  4. Rule combination: We kept your original Rule 1 logic and added new rules alongside it using additional when clauses, so all rules work together without conflicts.

This schema should now enforce all 5 validation rules you specified. Let me know if you need any tweaks or further clarification!

内容的提问来源于stack exchange,提问作者Tarni Baghel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 08:48:13