react select with form hook form submit - reactjs

this works fine on form submit shows selected value when I add onChange event then on form submit it doesnot show selected value
<Controller name="CostCenterGrp" className="form-control" control={control} render={({ field, value}) => ( <ReactSelect {...field} isClearable options={costCenterHeads} value={value} /> )}`

You need to add field.onchange inside the component to manual edit the value
field.onChange(event);
<Controller
render={({ field }) => <input onChange={event=>{
handleSampleChange(event);
field.onChange(event);
}} />}
name="sample"
control={control}
/>

Related

How to trigger re-render with `setValue` using react-hook-form?

I have a simple form with a select field, it's react-hook-form for validation and everything. There's a Controller which renders a Material UI Select. I would like to set the value of such select using setValue from outside the component (in the root of the form, where all controls reside).
This is the piece of code I'm using (slightly simplified not to waste too much of your time)
type Props = {
name: string;
control: Control<any>;
options: SelectOptions[];
};
const Select: FunctionComponent<Props> = ({
name,
control,
options,
}) => (
<Controller
control={control}
name={name}
render={({ field: { onChange, value } }) => {
return (
<FormControl>
<MuiSelect onChange={onChange}>
{options.map((o) => (
<MuiSelectItem key={o.key} value={o.value}>{o.label}</MuiSelectItem>
))}
</MuiSelect>
</FormControl>
)
}}
/>
);
As far as changing the value of the select, setValue works magically. When I feed a new value, it works as intended. The problem (I guess) is the component is not re-rendered, so the old value is still shown. I'm not sure how to fix this thing and docs did not help a lot. Any help is much appreciated, thanks!
As #knoefel said I tried setting the defaultValue="" but doesn't work for me(maybe because I am using FormProvider). So what I did is use watch instead of value
<Controller
name='name'
control={control}
render={({ field: { onChange } }) => (
<Select
dropdownValues={dropdownValues}
value={watch('name')}
onChange={onChange}
/>
)}
/>
I think you just forgot to set the value prop of <Controller /> to your <MuiSelect />. You also have to set a defaultValue for your <Controller /> field, either via the defaultValue prop or via useForm.
<Controller
control={control}
name={name}
defaultValue=""
render={({ field: { onChange, value } }) => {
return (
<FormControl>
<MuiSelect onChange={onChange} value={value}>
{options.map((o) => (
<MuiSelectItem key={o.key} value={o.value}>{o.label}</MuiSelectItem>
))}
</MuiSelect>
</FormControl>
)
}}
/>

How To implement ReactFlagsSelect with React Hook Form Controller

I tried to implement with React Hook From using <Controller />. While I am submitting the form country field return undefined.
<Controller
name="country"
control={control}
render={({ field: { onChange, value } }) => (
<ReactFlagsSelect
selected={selected}
onSelect={code => handleChange(code)}
value={value}
onChange={onChange}
/>
)}
/>
The problem is you pass RHF's onChange handler to the wrong prop. <ReactFlagsSelect /> doesn't have a onChange prop, instead you should pass it to the onSelect prop.
<Controller
name="country"
control={control}
render={({ field: { onChange, value } }) => (
<ReactFlagsSelect
selected={selected}
onSelect={onChange}
value={value}
/>
)}
/>
Side-note: RHF's will update value changes to your registered fields in it's internal form state, so there is no need to use extra state management for these values via useState or something similar. If you really need to call your handleChange callback, you can do both in the onSelect callback.
<Controller
name="country"
control={control}
render={({ field: { onChange, value } }) => (
<ReactFlagsSelect
selected={selected}
onSelect={code => {
onChange(code);
handleChange(code);
}}
value={value}
/>
)}
/>

React Hook Form and React Select Not Working as Expected

Im trying to wrap React Select inside of a React Hook Form with the Controller wrapper component as per the docs (https://react-hook-form.com/get-started#IntegratingControlledInputs)
<Controller
name="ShiftCaptain"
control={control}
render={({ field }) => (
<Select
{...field}
value={selectValue}
options={options}
placeholder={"Select Person"}
onChange={(e) => setSelectValue(e)}
/>
)}
/>
On form submission, the value captured inside the React Select isnt being populated into React Hook Forms:
Any ideas?
TIA
The field object of the render callback which you spread on your <ReactSelect /> component has a value and a onChange property, which RHF needs to link the value and also changes to the value to it's internal form state. Right now you overwriting this, so RHF can't update the value. Try this and it should work:
<Controller
name="ShiftCaptain"
control={control}
defaultValue={null}
render={({ field }) => (
<Select
{...field}
options={options}
placeholder={"Select Person"}
/>
)}
/>
If you want to set a default value for your select after page load you should use the <Controller /> defaultValue prop, which will pass the value to your <ReactSelect />.
Please check the this code sandbox.
https://codesandbox.io/s/react-hook-form-v7-controller-forked-40t3s?file=/src/index.js
const handleOnChange = (e) => {
setSelectedValue(e.value);
};
<label>React Select</label>
<Controller
name="ReactSelect"
control={control}
render={({ field }) => (
<ReactSelect
isClearable
{...field}
value={selectedValue}
onChange={handleOnChange}
options={[
{ value: "chocolate", label: "Chocolate" },
{ value: "strawberry", label: "Strawberry" },
{ value: "vanilla", label: "Vanilla" }
]}
/>
)}
/>

React Hook Form: when I render a TextField (materialUI) and provide the Field: {onChange} it says onChange undefined

I'm literally following their documentation and also tried the code from an article on github. I have the most recent version installed. Still not working. So frustateeeeeed.
const { control, handleSubmit } = useForm()
This is the component I return:
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="lastName"
control={control}
defaultValue=""
render={({ field, fieldState }) => (
<TextField
label="Last Name"
variant="filled"
value={field.value}
onChange={field.onChange}
error={!!fieldState.error}
helperText={fieldState.error ? fieldState.error.message : null}
/>
)}
rules={{ required: 'Last name required' }}
<Button type="submit" disabled={!stripe} buttonText="Pay"></Button>
</form>
It simply keeps giving the error that field.value, field.onchange, fieldState.error are undefined. I tried destructuring too. Doesn't work either.
Here is a working example: https://codesandbox.io/s/ancient-worker-mdqx3
I recommend passing the ref as well.

Register third party- custom component with react-hook-form

I am using react-hook-form and using third party DatePicker. Since it's a custom component using it as a controlled component to register it. This works fine
<Controller
control={control}
name="reviewStartDate"
render={({ field: { onChange, onBlur, value } }) => (
<DatePicker
className={`form-control ${errors.reviewStartDate ? 'is-invalid' : ''}`}
customInput={<input />}
wrapperClassName="datePicker"
onChange={onChange}
onBlur={onBlur}
selected={value ? new Date(value) : ''}
dateFormat='dd-MMM-yyyy'
/>
)}
/>
Similarly/however, I am using thirdparty Multiselect. Here the value is not being registered. It does show the selected value but when I submit the form the value is not present in data.
<Controller
control={control}
name="rootCauseAnalysisCategory"
render={({ field: { value } }) => (
<Multiselect
options={rootCauseAnalysisCategorys}
isObject={false}
showCheckbox={true}
hidePlaceholder={true}
closeOnSelect={false}
selectedValues={value}
/>
)}
/>
Similarly
The <MultiSelect /> component has onSelect and onRemove props, so you can just pass onChange to them. This will work because they both have the signature that the first argument is an array containing the current selected values.
<Controller
control={control}
name="rootCauseAnalysisCategory"
defaultValue={[]}
render={({ field: { value, onChange } }) => (
<Multiselect
options={rootCauseAnalysisCategorys}
isObject={false}
showCheckbox={true}
hidePlaceholder={true}
closeOnSelect={false}
onSelect={onChange}
onRemove={onChange}
selectedValues={value}
/>
)}
/>
UPDATE
If you want to access the current value for rootCauseAnalysisCategory, you have to use watch. Please note, that it is also important to either provide a defaultValue at the <Controller /> field level or call useForm with defaultValues. In the example i passed the defaultValue at the field level.
function App() {
const { control, handleSubmit, watch } = useForm();
const onSubmit = (data) => {
console.log(data);
};
const rootCauseAnalysisCategorys = ["Category 1", "Category 2"];
const rootCauseAnalysisCategory = watch("rootCauseAnalysisCategory");
return (
<div className="App">
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
control={control}
name="rootCauseAnalysisCategory"
defaultValue={[]}
render={({ field: { value, onChange } }) => (
<Multiselect
options={rootCauseAnalysisCategorys}
isObject={false}
showCheckbox={true}
hidePlaceholder={true}
closeOnSelect={false}
onSelect={onChange}
onRemove={onChange}
selectedValues={value}
/>
)}
/>
{rootCauseAnalysisCategory?.includes("Category 1") && <p>Category 1</p>}
<input type="submit" />
</form>
</div>
);
}

Resources