Recent Updates to API in Version 6.X:
- The validation option has undergone significant changes, now requiring the use of a resolver function wrapper and a different configuration property name.
Note: While documentation has been updated to reflect the change from validationResolver to resolver, code examples in the repository have not been updated yet (still using validationSchema for tests). It appears that there is some uncertainty surrounding the code implementation, so it may be best to avoid using their Controller until things are more settled. Alternatively, consider using the Controller as a thin wrapper for your own form Controller HOC, which seems to align with the direction they are headed.
see official sandbox demo for reference on unexpected behavior of "false" value as a string in the Checkbox
import { yupResolver } from "@hookform/resolvers";
const { register, handleSubmit, control, getValues, setValue } = useForm({
resolver: yupResolver(schema),
defaultValues: Object.fromEntries(
boats.map((boat, i) => [
`boat_ids[${i}]`,
preselectedBoats.some(p => p.id === boats[i].id)
])
)
});
Controller
no longer natively handles Checkbox (type="checkbox") or deals with values correctly. It fails to recognize boolean values for checkboxes and attempts to convert them to string values. Your options include:
- Avoid using
Controller
. Opt for uncontrolled inputs instead
- Utilize the new
render
prop to create a custom render function for Checkbox and incorporate a setValue hook
- Use Controller as a form controller HOC and manually manage all inputs
Examples demonstrating how to avoid the use of Controller:
https://codesandbox.io/s/optimistic-paper-h39lq
https://codesandbox.io/s/silent-mountain-wdiov
A similar example to the original one but utilizing the yupResolver wrapper
Description for Version 5.X:
Here is a simplified example that eliminates the need for Controller. The documentation recommends using an uncontrolled approach. It is advised to assign each input its unique name and filter/transmute the data to exclude unchecked values, such as demonstrated with Yup and validatorSchema in the latter example. However, in the context of your example, sharing the same name leads to the aggregation of values into an array that meets your requirements.
https://codesandbox.io/s/practical-dijkstra-f1yox
An issue arises when the structure of your checkboxes doesn't align with your defaultValues. It should be { [name]: boolean }, where names generated are the literal string boat_ids[${boat.id}], until they pass through the uncontrolled form inputs that consolidate the values into a single array. For instance, form_input1[0] form_input1[1] results in form_input1 == [value1, value2]
https://codesandbox.io/s/determined-paper-qb0lf
Constructing defaultValues: { "boat_ids[0]": false, "boat_ids[1]": true ... }
Controller anticipates boolean values for toggling checkbox states and uses these values as defaults fed to the checkboxes.
const { register, handleSubmit, control, getValues, setValue } = useForm({
validationSchema: schema,
defaultValues: Object.fromEntries(
preselectedBoats.map(boat => [`boat_ids[${boat.id}]`, true])
)
});
The schema employed for validationSchema ensures at least two choices are made and transforms the data to the desired format before submission. It filters out false values, resulting in an array of string IDs:
const schema = Yup.object().shape({
boat_ids: Yup.array()
.transform(function(o, obj) {
return Object.keys(obj).filter(k => obj[k]);
})
.min(2, "")
});