I have a form that has an collection of checkboxes where the name is: choices[]. I have a PHP backend and the name of the checkboxes cant change. I'm trying to build the Yup schema to create a validation rule where one of the choices has to be picked.
My current solution is to have an onchange the updates a hidden field with a value. This value is what is validated against. But that cant be right.
Any idea? I've tried, but this isnt working. I cant seem to find a good example of this on the web so i've decided to ask here.
choices[]: Yup.boolean().required('error we need to pick one')
EDIT to add in some code:
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
My component essentiall renders the following html:
<div>
<checkbox name='choices[]' value='car'> Car<br />
<checkbox name='choices[]' value='van'> Car<br />
<checkbox name='choices[]' value='bike'> Car<br />
</div>
I use formik for my validation using a validation schema like so:
<Formik
enableReinitialize
initialValues={postingForm.initialValues}
validationSchema={postingForm.validationSchema}
>
{form => (
<Form> ....</Form>
)}
</Formik>
On submit i want to validate that at least one of my choices has been checked. My current component will +1 and -1 the value of a hidden field based on checked status for a checkbox. This is validated using:
cbxSFVal: Yup.number().min(1, required_message),
But i'm sure there must be an easier way to validate the checkboxes.