How to make datepicker work with react hook form? - javascript

I have a short code below, the date picker works fine, it changes when I select other dates.
But i can't figure it out why it always fail in required validation even I already select a date.
<Controller
control={control}
name="disclosureDate"
rules={{ required: 'This field is required' }}
errors={errors.disclosureDate}
value={disclosureDate}
render={({ field }) => (
<InputDate
className="mb-px-8"
onChange={(value) => setDisclosureDate(value)}
value={disclosureDate}
/>
)}
/>
I've been following of these links, but I can't make it work in my end.
react-hook-link-Controllers
stackoverflow-link
(by the way, there are other validations aside from required, for demonstration purposes only)

I don't think you are using the Controller correctly. You should use the value and onChange it provides in the render prop, try -
<Controller
control={control}
name="disclosureDate"
rules={{ required: 'This field is required' }}
errors={errors.disclosureDate}
value={disclosureDate}
render={({ value, onChange }) => (
<InputDate
className="mb-px-8"
onChange={onChange}
value={value}
/>
)}
/>

Related

React-hook-form conditional required validation based on other field

I have a project with nextjs and typescript in this project I've used react-hook-form for handling my forms. In one of my forms I have a checkbox and if that check box, be checked the Date input should be disabled and unrequired and otherwise the date input should be required.
I saw this solution
React-hook-form conditional validation of text field, based on if another checkbox is checked?
but I use Controller approach and I can't pass function into required this is my inputs
<div className='flex items-center gap-8'>
<InputWrapper
hasError={!!errors.expirationDate?.message}
errorMessage={errors.expirationDate?.message}
required
label='تاریخ انقضا'
disabled={isFormDisabled || watch('neverExpired')}>
<Controller
name="expirationDate"
control={control}
rules={{
required: {}
}}
render={({field}) => (
<CustomizedDatePicker
value={field.value}
minDate={new Date()}
name='expirationDate'
onChange={(date: DateObject) => {
field.onChange(date ? date.unix * 1000 : '');
}}
disabled={isFormDisabled || watch('neverExpired')}
/>
)}
/>
</InputWrapper>
<InputWrapper
labelBesideInput
hasError={!!errors.neverExpired}
label="هرگز منقضی نشود"
id={'neverExpireCheck'}
className={'pt-6'}
disabled={isFormDisabled}
>
<Controller
name="neverExpired"
control={control}
render={({field}) => (
<Checkbox
inputId={field.name}
onChange={(e) => field.onChange(e.checked)}
checked={field.value}
disabled={isFormDisabled}
/>
)}
/>
</InputWrapper>
tnx in advance for any effort
The best way is to use validation schemas such as Zod or yup, and you can manipulate the schema by the value of watch('neverExpired').

How can i make controller component for Form Element

In react native I want to make a dynamic controller component. But i cant access errors with it. I using "react-hook-form" for form elements. So Its my component :
const {
control,
handleSubmit,
formState: {errors},
setValue,
} = useForm();
const DynamicController = ({req, pattern, name, label}) => {
return (
<>
<Text style={[t.textBase]}>{label}</Text>
<Controller
control={control}
defaultValue=""
rules={{
required: {
value: true,
message: 'Bu alan boş bırakılamaz!',
},
}}
render={({field: {onChange, onBlur, value}}) => (
<Input
errorText={errors[name].message}
error={errors[name]}
onBlur={onBlur}
placeholder={label}
onChangeText={onChange}
value={value}
/>
)}
name={name}
/>
</>
);
};
My Input Component is basicly simple input. My problem is when i give error name like that example i cant access errors.
Its how i use my component :
<DynamicController
label="Email"
name="Email"
pattern={true}
req={true}
/>
When i dont fill the element and log the submit its not showing any error. Its simple passing validate. So what can i do where do i make wrong ? thank you for answerings!!!
Is your Input a custom wrapper? If not, a better way do this using react-hook-form would be:
const {
control,
handleSubmit,
formState: {errors},
setValue,
} = useForm(
defaultValues: {
firstName: '', // form fields should be populated here so that the error can be displayed appropriately
lastName: ''
}
);
const DynamicController = ({req, pattern, name, label}) => {
return (
<>
<Text style={[t.textBase]}>{label}</Text>
<Controller
control={control}
defaultValue=""
rules={{
required: {
value: true,
message: 'Bu alan boş bırakılamaz!',
},
}}
render={({field: {onChange, onBlur, value}}) => (
<Input
onBlur={onBlur}
placeholder={label}
onChangeText={onChange}
value={value}
/>
)}
name={name}
/>
{errors[name] && <Text>This is required.</Text>}
</>
);
};

React Hook Form dynamic required

I'm trying to make a form with two fields using react hook form where the required value of the text field depends on the value of the select drop down.
Here is my code:
const { handleSubmit, control, errors } = useForm();
const [isPickupPoint, togglePickupPoint] = useState(false);
const handleDestinationTypeChange: EventFunction = ([selected]) => {
togglePickupPoint(selected.value === "PICKUP_POINT");
return selected;
};
<Grid item xs={6}>
<InputLabel>Destination type</InputLabel>
<Controller
as={Select}
name="destinationType"
control={control}
options={[
{ label: "Pickup point", value: "PICKUP_POINT" },
{ label: "Shop", value: "SHOP" },
]}
rules={{ required: true }}
onChange={handleDestinationTypeChange}
/>
{errors.destinationType && (
<ErrorLabel>This field is required</ErrorLabel>
)}
</Grid>
<Grid item xs={6}>
<Controller
as={
<TextField
label="Pickup Point ID"
fullWidth={true}
disabled={!isPickupPoint}
/>
}
control={control}
name="pickupPointId"
rules={{ required: isPickupPoint }}
/>
{errors.pickupPointId && (
<ErrorLabel>This field is required</ErrorLabel>
)}
</Grid>
<Grid item xs={12}>
<Button
onClick={onSubmit}
variant={"contained"}
color={"primary"}
type="submit"
>
Save
</Button>
</Grid>
The isPickupPoint flag changes properly because the disabled prop of the textfield works fine. Only when the PICKUP_POINT option is selected the text field is active. But the required prop is not working, it is always false. When I try submitting the form when its empty the destinationType error label appears, but when I try to submit the form with the PICKUP_POINT option and empty pickupPointId field it passes with no errors.
How can I make this dynamic required prop work?
Based on the code here, it looks like isPickUpPoint is working as expected since it works for disable. Since you are using the same property for required, it should flow through. I would suspect that the bug may lie in your Controller component. I would take a look there and make sure that the property is what you expected to be.
Also for disabled the condition is !isPickUpPoint, so it will trigger when it's false.
For required the condition is isPickUpPoint so it will trigger when it's true.
That's also a bit of a disconnect since it looks like it's the same input.

Why required check not working after removing element?

Could you please tell why my required check is not working in autocomplete .I am using material UI with react hook form.
Step to reproduce
Click Submit button it show field is required.
then select any element from list.
remove the selected element Then click again submit button.It should
show “required” field check.but it is not showing anything why ??
Here is my code
https://codesandbox.io/s/mui-autocomplete-with-react-hook-form-0wvpq
<Controller
as={
<Autocomplete
id="country-select-demo"
multiple
style={{ width: 300 }}
options={countries}
classes={{
option: classes.option
}}
autoHighlight
getOptionLabel={option => option.label}
renderOption={(option, { selected }) => (
<React.Fragment>
<Checkbox
icon={icon}
checkedIcon={checkedIcon}
style={{ marginRight: 8 }}
checked={selected}
/>
{option.label} ({option.code}) +{option.phone}
</React.Fragment>
)}
renderInput={params => (
<TextField
{...params}
label="Choose a country"
variant="outlined"
fullWidth
name="country"
inputRef={register({ required: true })}
// required
error={errors["country"] ? true : false}
inputProps={{
...params.inputProps,
autoComplete: "disabled" // disable autocomplete and autofill
}}
/>
)}
/>
}
onChange={([event, data]) => {
return data;
}}
name="country"
control={control}
/>
When the form loads initially, the value of your form is an empty object -
{}
When you select a country (say, 'Andorra') the value of your form becomes:
{"country":[{"code":"AD","label":"Andorra","phone":"376"}]}
And then when you deselect the country, the value of your form becomes:
{"country":[]}
An empty array technically meets the "required" criteria (it's not null, after all) so your required handler doesn't fire.
You can verify this is happening by showing the value of the form in your App class -
const { control, handleSubmit, errors, register, getValues } = useForm({});
return (
<form noValidate onSubmit={handleSubmit(data => console.log(data))}>
<Countries control={control} errors={errors} register={register} />
<Button variant="contained" color="primary" type="submit">
Submit
</Button>
<code>{JSON.stringify(getValues())}</code>
</form>
);
The simple fix is to NOT return an empty array as a value from your control - update your onChange handler as follows -
onChange={([event, data]) => {
return data && data.length ? data : undefined;
}}

onChange handler doesn't fire when using custom-component

I'm using Formik for validation in a React app.
Validation is working correctly, but my onChange handler does not fire:
<Field
type="text"
name="name"
placeholder="First Name"
component={Input}
onChange={() => console.log("gfdg")}
/>
Link to Sandbox
Why is this?
Inside Input, the way you have ordered the props passed to your input element means your onChange is being overwritten by Formik's onChange. When you create a Field with a custom component (i.e. Input in your case), Formik passes its FieldProps to the component. FieldProps contains a property field that contains various handlers including onChange.
In your Input component you do this (I've removed the irrelevant props):
<input
onChange={onChange}
{...field}
/>
See how your own onChange will just get replaced by Formik's onChange() inside field? To make it clearer ...field is basically causing this to happen:
<input
onChange={onChange}
onChange={field.onChange}
// Other props inside "field".
/>
If you were to reorder those the console message will now appear:
<input
{...field}
onChange={onChange}
/>
However now your input won't work now because you do need to call Formik's onChange to let Formik now when your input changes. If you want both a custom onChange event and for your input to work properly you can do it like this:
import React from "react";
import { color, scale } from "./variables";
const Input = React.forwardRef(
({ onChange, onKeyPress, placeholder, type, label, field, form }, ref) => (
<div style={{ display: "flex", flexDirection: "column" }}>
{label && (
<label style={{ fontWeight: 700, marginBottom: `${scale.s2}rem` }}>
{label}
</label>
)}
<input
{...field}
ref={ref}
style={{
borderRadius: `${scale.s1}rem`,
border: `1px solid ${color.lightGrey}`,
padding: `${scale.s3}rem`,
marginBottom: `${scale.s3}rem`
}}
onChange={changeEvent => {
form.setFieldValue(field.name, changeEvent.target.value);
onChange(changeEvent.target.value);
}}
onKeyPress={onKeyPress}
placeholder={placeholder ? placeholder : "Type something..."}
type={type ? type : "text"}
/>
</div>
)
);
export default Input;
See it here in action.
Although overall I'm not really sure what you're trying to do. Your form is working fine, you probably don't need a custom onChange but maybe you have some specific use case.
Let me first make it clear this answer is just for help purpose and I do know that this question has been accepted but I do have some modification for above answer with my version if the above solution doesn't work for anyone
Here onChangeText will return the value of the quantity field
<Formik
initialValues={{ product_id: '', quantity: '', amount: '' }}
onSubmit={(values, actions) => {
this.submitLogin(values);
}}
//some other elements ....
<Field placeholder='No. of Quantity' name='quantity' component={CustomInputComponent}
onChangeText={value => {
console.warn(value); // will get value of quantity
}}
/>
/>
Outside of your class you can define your component
const CustomInputComponent = ({
onChangeText,
field, // { name, value, onChange, onBlur }
form: { touched, errors, isValid, handleBlur, handleChange, values, setFieldValue }, // also values, setXXXX, handleXXXX, dirty, isValid, status, etc.
...props
}) => {
return (
<Input {...field} {...props} onBlur={handleBlur(field.name)}
onChangeText={value => {
setFieldValue(field.name, value);
onChangeText(value); // calling custom onChangeText
}}
/>
)
}

Categories