React Hook Form - Rules.Validate not triggered - reactjs

I have the following field with a RHF controller and a MUI Textfield:
<Controller
control={control}
name="name"
defaultValue=""
rules={{
required: true,
minLength: 3,
maxLength: 300,
validate: wtf,
}}
render={({ field, fieldState: { error } }) => (
<TextField
{...field}
fullWidth
label="Name"
size="small"
helperText={formState?.errors?.name?.message}
error={error !== undefined}
/>
)}
/>
The wtf method isn't getting called on input change. I've tried with different revalidate modes but this is just not firing at all. Am I missing something here? I've checked examples and tutorials and they all seem to do it this way.

I created a sandbox here and it works perfectly.
I only had to add {mode: "onChange"} inside the useForm method call and return a string if the validation function failed.
I based my improvements in the documentation for register options as it is recommended here in the rules section of the Controller component.
Feel free to ask for any further help.
-Ado

Related

PrimeReact number input field with react-hook-form

I currently have the following code in my application:
<Controller defaultValue={0.0} name={"create_lng"}
control={createControl} rules={{
required: {value: true, message: t("pleaseSiteLng")}
}}
render={({field, fieldState}) => (
<InputNumber minFractionDigits={2}
mode={"decimal"}
className={classNames(
{"p-invalid": createErrors.create_lng})}
id={field.name} {...field} />
)}/>
Here I would now expect to be able to enter decimal numbers as defined.
But as soon as I enter anything in the input field, even numbers, the value changes to NaN and is displayed.
This only occurs with the InputNumber component, all other components can be filled without problems and also display the desired values.
I have seen that there is a property from react-hook-form "valueAsNumber", but I haven't found anything how to use it in a controller.
Does anyone here know how I can solve the problem?Does anyone here know how I can solve the problem?
I have updated this ticket: https://github.com/primefaces/primereact/issues/2547
I think there needs to be showcase example on how to use InputNumber with React Hook Forms if it is not straightforward like you are seeing.
Edit 07/30/2022:
I have it working and here are two examples:
Price example must be between 0 and 250,000.
<Controller name="price" control={control} rules={{ required: 'Price is required.', min: 0, max: 250000 }} render={({ field, fieldState }) => (
<>
<label htmlFor={field.name} className={classNames({ 'p-error': errors.price })}>Price*</label>
<InputNumber id={field.name} ref={field.ref} value={field.value} onBlur={field.onBlur} onValueChange={(e) => field.onChange(e)} mode="currency" currency="USD" locale="en-US" inputClassName={classNames({ 'p-invalid': fieldState.error })} />
{getFormErrorMessage(fieldState)}
</>
)} />
Year example must be between 1970-2030:
<Controller name="year" control={control} rules={{ required: 'Year is required.', min: 1970, max: 2050 }} render={({ field, fieldState }) => (
<>
<label htmlFor={field.name} className={classNames({ 'p-error': errors.year })}>Year*</label>
<InputNumber id={field.name} ref={field.ref} value={field.value} onBlur={field.onBlur} onValueChange={(e) => field.onChange(e)} useGrouping={false} inputClassName={classNames({ 'p-invalid': fieldState.error })} />
{getFormErrorMessage(fieldState)}
</>
)} />
I encountered the same issue when working with Primereact InputNumber and Formik.
In my case the reason for unexpected behavior of InputNumber component is primereact custom onChange method of InputNumber:
onChange?(e: InputNumberChangeParams): void
interface InputNumberChangeParams {
originalEvent: React.SyntheticEvent;
value: number | null;
}
(Compared to InputText onChange property: onChange?: ChangeEventHandler<HTMLInputElement> | undefined )
formik.handleChange(e) expects e: React.ChangeEvent<any> which means I can't pass (e: InputNumberChangeParams) to the function. The solution for me was to use another function to handle the change and work only with e.value which is provided by InputNumber onChange method.
onChange={(e): void => {
formik.setFieldValue("fieldName", e.value);
}}

React-Final-Form delays in taking input with render props in Field

I am currently working on a react project. I am using react-final-form for fetching the data in the form. As I am using the material UI component to create the form I am creating the form somewhat like this.
Code
<Form
onSubmit={onSubmit}
validate={validate}
render={({ handleSubmit, values }) => (
<form onSubmit={handleSubmit}>
<FormControl variant="outlined" className={classes.formControl} key={fieldKey}>
<Field
name={field.fieldName}
render={({ input }) => (
<TextField
{...input}
className={classes.textField}
variant="outlined"
label={props.field.label}
placeholder={props.field.description}
required={props.field.isMandatory}
InputLabelProps={{
shrink: true,
}}
/>
)}
type="text"
/>
</FormControl>
</form>
)}
/>
Now as soon as I remove the input props from the render props it is working fine. but with the input props, it delays in taking input. Without input props, I could not fetch the value from the form.
Is there any way to resolve this time delay?
Thanks in advance.
If you want a simple field. Maybe you can pass on only essential props.
<TextField
name={input.name}
value={input.value}
onChange={input.onChange}
/>
The solution to this is subscriptions.
The form is initially rendered on every action, react-final-form allows to handle subscription,
<Form subscription={{handeleSubmit: true}} ...> </Form>
We can do somewhat like this
There is a video link for this. Video
Hope you find this helpful 😉

Antd RangePicker Component with React Hook Form

I currently have a react-hook-form managed form that I've added an antd RangePicker to. I'm having issues with updates to the RangePicker getting passed to the form object. Currently, the default values are passing fine but it's not taking any changes.
OnChange events seem to be being handled by the standard Controller method with the other field types (Input, etc.). My guess is I have to write something custom here but I'm not sure. Thanks in advance for any help.
Here is my current antd DatePicker that is being managed with react-hook-forms Controller method.
EDIT: Updated my code to use the render method in react-hook-form v6+ as opposed to the as method. I also noticed if I don't pass any defaultValue then the RangePicker accepts and passes both the start and end dates fine. But when I set the defaultValue it always returns the default start date twice.
<Controller
name="materialarrivalpickup"
control={control}
defaultValue={[
moment(user.project.projectmaterialarrival),
moment(user.project.projectmaterialpickup),
]}
rules={{ required: true }}
render={(props) => (
<RangePicker
{...props}
format="MM/DD/YYYY"
onChange={(e) => {
props.onChange(e);
console.log("Range Picker " + e);
}}
/>
)}
/>
Figured this out. Apparently, react-hook-form was properly passing the RangePicker changes to my form object I just couldn't tell based on the log.
When I update the picker the Moment object (two dates) wasn't looking updated in the log produced by react-hook-form watch() (both look like they're 3/3/2020).
But when I expand the Moment object I'm getting my updated dates (3/3/2020 and 3/5/2020).
I'll leave my working RangePicker + react-hook-form code here for anyone else that needs it.
<Controller
name="materialarrivalpickup"
style={{ marginBottom: "8px" }}
control={control}
defaultValue={[
moment(user.project.projectmaterialarrival),
moment(user.project.projectmaterialpickup),
]}
rules={{ required: true }}
render={(props) => (
<RangePicker
{...props}
format="MM/DD/YYYY"
onChange={(e) => {
props.onChange(e);
console.log("Range Picker: " + e);
}}
/>
)}
/>

Ant.design does not detect custom input component in Form.Item React

So, the main problem is, that antd form does not detect my custom input based on antd standard input:
There is a piece of form code (AddProduct):
<Form.Item
className="m-t-10"
name="price"
rules={[
{
required: true,
message: `${t('FORM.ERR.SHOP.PRICE')}`,
},
]}
>
<CurrencyInput size="small" placeholder={t('FORM.SHOP.PRICE_VAT')} name="price" />
</Form.Item>
There is my custom input (CurrencyInput):
return (
<Input size={props.size} placeholder={props.placeholder} name={props.name} type="number" prefix={settings[6].value} />
)
The problem is when I try to submit the form it does not detect currency input, throws err that this field is required. Any ideas are it possible to implement custom input, basically, it's more HOC than custom input
You need to pass to your custom component all props, because Form.Item pass to there onChange and value props
function CustomInput({size, placehodler, name, ...restProps}) {
return (
<Input size={size} placeholder={placeholder} name={name}
type="number" prefix={settings[6].value} {...restProps} />
)
}

How to make autocomplete field of material UI required?

I have tried a couple of ways in order to make the material UI's autocomplete field of type required but I am not getting the behavior that I wanted. I had encapsulated my field inside react hook form <Controller/> yet no luck. I want to trigger message 'Field is mandatory' on submit when nothing is added to the field.
Below is the code snippet, I have not removed comments so that it becomes a bit easier for others to understand the approach that I had followed earlier -
<Controller
name="displayName"
as={
<Autocomplete
value={lists}
multiple
fullWidth
size="small"
limitTags={1}
id="multiple-limit-lists"
options={moduleList}
getOptionLabel={(option) => option.displayName}
renderInput={(params,props) => {
return (
<div>
<div className="container">
<TextValidator {...params} variant="outlined" label="Display Name*" className="Display Text"
name="displayName" id="outlined-multiline-static"
placeholder="Enter Display-Name" size="small"
onChange={handleDisplay}
// validators={['required']} this and below line does throw a validation but the problem is this validation stays on the screen when user selects something in the autocomplete field which is wrong.
// errorMessages={['This field is required']}
// withRequiredValidator
/>
</div>
</div>
)
}}
/>
}
// onChange={handleDisplay}
control={control}
rules={{ required: true }}
// required
// defaultValue={options[0]}
/>
<ErrorMessage errors={errors} name="displayName" message="This is required" />
You can use the following logic to get it worked. Though this might not be the best solution but works.
<Autocomplete
renderInput={(params) => (
<TextField
{...params}
label={value.length === 0 ? title : title + " *"} //handle required mark(*) on label
required={value.length === 0}
/>
)}
/>
I tried using the built in required in textfield for autocomplete, and it works like a charm. Maybe you can use this as a reference.
<Autocomplete
renderInput={(params) => {
<TextField {...params} required />
}
// Other codes
/>
Since you are rendering <TextValidator>, you should apply mandatory(required) attribute to that component not on <AutomComplete>.
Try this if your Material UI version is v5
<TextField
{...params}
required
label="Tags"
value={value}
InputProps={{
...params.InputProps,
required: value.length === 0,
}}
/>

Resources