Yup将架构映射到元素的choices [](react和formik)

时间:2019-09-09 14:07:42

标签: reactjs formik yup

我有一个表单,其中包含多个复选框,其名称为:choices []。我有一个PHP后端,复选框的名称无法更改。我正在尝试构建Yup模式以创建验证规则,其中必须选择其中一项。

我当前的解决方案是通过onchange更新带有值的隐藏字段。该值是针对其进行验证的。但这不可能是对的。

有什么主意吗?我已经尝试过了,但这是行不通的。我似乎无法在网上找到一个很好的例子,所以我决定在这里问。

choices[]: Yup.boolean().required('error we need to pick one')

编辑以添加一些代码:

import React, { ChangeEvent, useState, useEffect } from 'react'

import Checkbox from ...
import CheckboxProps from ...
import CheckboxGroup from ...
import Label from ...

export interface CheckboxGroupChoicesProps {
  setFieldValue?: any
}

/**
 *
 * @param props
 */
const CheckboxGroupChoices: React.FunctionComponent<
  CheckboxGroupChoicesProps
> = props => {
  /**
   * State management for the checked counter, we use this in a hidden field for validation purposes
   */
  const [checkedCounter, setCheckedCounter] = useState(0)
  const [initialLoad, setInitialLoad] = useState(1)
  const hiddenFieldName = 'cbxSFVal'

  /**
   * Enable validation on this checkbox field
   *
   * This is a required field, as such we need to ensure that at least one of the
   * checkboxes has been selected. By incrementing the <hidden> field we ensure
   * that we have an idea on how many of the checkboxes have been selected. We
   * then use this within the validation.tsx to do some stuff.
   *
   * @param e: ChangeEvent
   */
  function validateCheckboxRequired(e: ChangeEvent) {
    if ((e.currentTarget as HTMLInputElement).checked) {
      setCheckedCounter(checkedCounter + 1)
    } else {
      setCheckedCounter(checkedCounter - 1)
    }
  }

  /**
   * Handle the state change for checkedCounter.
   * setFieldValue is from formik and we can use it to update the hidden field
   * that we use for validation.
   */
  useEffect(() => {
    if (initialLoad != 1) {
      props.setFieldValue(hiddenFieldName, checkedCounter)
    } else {
      setInitialLoad(0)
    }
  }, [checkedCounter])

  /**
   * Create an array of checkboxes that will be sent to the Checkboxgroup molecule.
   *
   * @return Array<ChecboxProps>
   */
  const getCheckboxes: any = () => {
    const checkboxes: Array<React.ReactElement<CheckboxProps>> = []
    const options = ['Car', 'Van', 'Bike']

    options.forEach((option, key) => {
      checkboxes.push(
        <Checkbox
          label={option}
          value={option}
          disabled={false}
          name={'choices[]'}
          key={`choices-${key}`}
          handleOnClick={(e: ChangeEvent) => validateCheckboxRequired(e)}
        />
      )
    })

    return checkboxes
  }

  return (
    <>
      <Label>Pick choices</Label>
      <CheckboxGroup columns={3}>{getCheckboxes()}</CheckboxGroup>
      <input type={'hidden'} name={hiddenFieldName} />
    </>
  )
}

export default CheckboxGroupChoices

我的组件essentiall呈现以下html:

<div>
<checkbox name='choices[]' value='car'> Car<br />
<checkbox name='choices[]' value='van'> Car<br />
<checkbox name='choices[]' value='bike'> Car<br />
</div>

我使用formik进行如下验证模式的验证:

<Formik
    enableReinitialize
    initialValues={postingForm.initialValues}
    validationSchema={postingForm.validationSchema}
>
{form => (
  <Form> ....</Form>
)}
</Formik>

提交后,我想确认是否已检查我的至少一项选择。我当前的组件将基于复选框的选中状态来+1和-1隐藏字段的值。使用以下方法对此进行了验证:

cbxSFVal: Yup.number().min(1, required_message),

但是我敢肯定,必须有一种更简单的方法来验证复选框。

1 个答案:

答案 0 :(得分:1)

您需要使用引号设置属性名称。

const schema = Yup.object().shape({
  "choices[]": Yup.boolean().required('error we need to pick one')
});

此外,请确保您以正确的方式访问属性。

// Syntax Error
obj.choices[]

// Correct Way
obj["choices[]"]

编辑:

您可以做的是使用每个复选框的状态创建一个数组,因此,如果您有3个选项,它将是一个长度为3且带有false的数组,并在单击时将其更新为true。

这样,您可以通过以下方式验证其中一个复选框为真

"choices[]": Yup.array().oneOf(['true']).required('error we need to pick one')