Input not writing into input field.. Issue caused by React useForm Hook register validations - reactjs

const { register, handleSubmit, errors, setValue } = useForm();
<div className="col pl-0 pr-3">
<FormInput
id="id"
name="name"
isAllowed={e => e.value == '' || (e.value.length <= 14 && e.floatValue >= 0)}
allowLeadingZeros={true}
decimalScale={0}
onChange={e => setName(e.target.value)}
value={Name}
ref={register({ required: { value: true, message: "Please enter name" } })}
/>
<ErrorMessage
errors={errors}
className="col-md-6"
name="name"
as="small"
/>
</div>
In above mentioned code,, here FormInput is customized from StyledInput.
After displaying invalid message, when I am trying to enter something in input field, first character is not writing in field but it is clearing invalid error message from second character writing into field. What's the problem How to solve it Can anyone help me on this ?

UPDATED
By using control input, 3rd party library can work with react-hook-form.
https://react-hook-form.com/get-started#IntegratingControlledInputs
<Controller
as={
<NumberFormat
thousandSeparator={true}
allowLeadingZeros={true}
decimalScale={0}
onValueChange={(value) => {
console.log(value);
}}
isAllowed={(e) =>
e.value === "" || (e.value.length <= 14 && e.floatValue >= 0)
}
/>
}
id="id"
name="name"
defaultValue="1234"
control={control}
rules={{
required: true,
minLength: 2
}}
/>
There is no need to use another state to control the value.
The component is register in react-hooks-form with name "name", it will create the name state and handled state change for you.
Remove the following lines:
const [name, setName] = useState(); // I think you have your own name state, remove it
value={name} // remove it
onChange={(e) => setName(e.target.value)} // remove it

Related

How can I check if the value of the inputs is the same?

I have a form where two fields have to have the same value to be able to continue with the process, for this I have created a component that is in charge of the comparison, the problem is that it does not show me the value of the input to be able to make the comparison . this is my component.
const UIInput = ({ register, rules, name, errors, label, type, options, equals, getValues, ...props }) => {
return (
<div>
<label >{label}</label>
{type === 'select' ?
<select
{...(register && register(name, rules))}>
{options.map(o => (
<option key={o}>{o}</option>
))}
</select>
:
<input
name={name}
{...props}
placeholder={label}
/* {...(register && register(name, rules))} */
{...(register && register({validate:{
name:value=>(value === getValues().email) || console.log('are not the same')
}}))}
/>
/* register && register(name, rules)) */
}
{errors[name] && <ErrorMessaje>{errors[name]?.message}</ErrorMessaje>}
</div>
)
}
export default UIInput
And this is how I use it:
<UIInput
name="email"
register={register}
errors={errors}
label="Email"
defaultValue={dataForm.email}
type="email"
rules={{ required: 'Enter an email' }}
/>
<UIInput
name="email2"
register={register}
errors={errors}
label="Confirmar Email"
type="email"
rules={{ required: 'Has to be the same value' }}
getValues={getValues}
/>
when I run the code the error it sends me is "path.split is not a function"

How can i put value in input?

Why can't I put a value in the input? The problem is: I need to put a 'name' in <Form.Item> to apply the rules. Without that, the rules will not be able to work, but if you remove the name="userName" from <Form.Item the value appears at the input.
How can i solve that?
<Form autoComplete="off" layout="vertical" onFinish={handleFinish}>
<Form.Item name="userName" rules={getTextRule('name')}>
<Input value={fields?.firstName} name="firstName" onChange={(e) => {
handleInputChange(e)
}} />
</Form.Item>
</Form.Item>
simple we can code like
const [text,setText] = useState('')
return(
<input type='text' value={text} onChange={e=>setText(e.target.value)}/>
)
If you use the form you can let Ant Form manage the state by removing the value & the onChange props on the <Input />.
Else if you manage the state by yourself make sure to get the value from the e.target.value.
ex:
const [fields, setFields] = useState({})
const handleOnChange = (e) => {
setFields((state) => {
...state,
[e.target.name]: e.target.value,
})
}
return (
<Input
name="firstName"
value={fields.firstName}
onChange={handleOnChange}
/>
)

Conditional Error Handling on MUI controls in react hook form

I want to make field mandatory on the base of condition. Here is my code snippet
<Controller
name={"InvoicingAddress.address_line_1"}
control={control}
rules ={{
required: "This field is required"
}}
render={({ field: { onChange, value },
}) => (
<Input
theme={theme}
fullWidth={true}
label={"Address Line 1"}
placeholder="House number, street name"
type="text"
onChange={onChange}
value={value}
error={errors?.InvoicingAddress?.address_line_1?.message}
></Input>
)}
/>
I want to make required on the basis of condition:
something like this:
{condition &&
rules ={{
required: "This field is required"
}}
}
but the above code is not working
After a lot of research, I've solved something like this
const [applyValidation, setApplyValidation] = useState<boolean>(false);
function setError(): boolean {
if(got error depending upon your condition)
return true;
else
return false;
}
<Controller
name={"OfficeAddress.City"}
control={control}
rules={{
required: {
value: applyValidation,
message: ValidationMessages.CITY_REQUIRED
}
}}
render={({ field: { onChange, value } }) => (
<Input
theme={theme}
fullWidth={true}
label={"City"}
placeholder="e.g. company, apartment, building..."
type="text"
onChange={(e) => {
onChange(e)
setApplyValidation(setError());
}}
value={value}
error={errors?.OfficeAddress?.City?.message}
></Input>
)}
/>

react-hook-form: unregister doesnt clear component value

i have one text field which i am manually unregistering. it is successfully getting unregister and data is excluded from formdata, however user entered value still stays in the text field. i am expecting value also get cleared from component as well. i even tried
setValue('fieldName',"")
is not working. not sure if i am doing something wrong.
so if i re register my text field and trigger validation, you will see required field validation but value is still present in text field
code below:
const App = () => {
const { register, handleSubmit, unregister, errors, setValue } = useForm();
const onSubmit = (data) => {
alert(JSON.stringify(data));
};
useEffect(() => {
register("person.firstName", { required: true });
register("person.lastName", { required: true });
// }
}, [register]);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label>First Name</label>
<input
type="text"
name="person.firstName"
onChange={(e) => setValue("person.firstName", e.target.value)}
/>
{errors?.person?.firstName && <p> First name required</p>}
<label>Last Name</label>
<input
type="text"
name="person.lastName"
onChange={(e) => setValue("person.lastName", e.target.value)}
/>
{errors?.person?.lastName && <p> Last name required</p>}
<button
type="button"
onClick={() => {
setValue("person.lastName", "");
unregister("person.lastName");
}}
>
unregister lastName
</button>
<input type="submit" />
</form>
);
};
here is my CSB
i would appreciate any help
the error occurs because you apply your register at useEffect:
useEffect(() => {
register("person.firstName", { required: true });
register("person.lastName", { required: true });
// }
}, [register]);
instead, if you apply to ref at your input fields setValue("person.lastName", "") will clear the field as expected:
<input
ref={register({ required: true })}
type="text"
name="person.firstName"
onChange={(e) => setValue("person.firstName", e.target.value)}
/>

Trying to use react-hook-form in combination with react-input mask

I have the following setup. My mask will show up, but when I type in it it just skips to the end of the line I am not quite sure what I am doing wrong here. I have tried putting all the props in the parent component and passing them all with a spread, That didn't work. I can provide more debugging if someone can give me an idea on where to debugg first and I'll do it.
Thanks ahead of time
import React from "react"
import { useForm } from "react-hook-form"
import MaskedInput from "react-input-mask"
const Quote = () => {
const { register, handleSubmit, watch, errors } = useForm();
const [tel, setTel] = React.useState("");
render(
<MaskedInput
mask="(780) 000-0000"
alwaysShowMask
onChange={(e) => setTel(e.target.value)}
value={tel}
name={data.title}
>
{(inputProps) => (
<input
ref={register({
required: true,
pattern: /^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/im,
})}
value={inputProps.tel}
name={inputProps.name}
{...inputProps}
/>
)}
</MaskedInput>
);
};
For those who are using react-hook-form version 7, here is an example how to get it to work:
<Controller
name="your input name"
control={control}
defaultValue=""
rules={{
required: true,
}}
render={({ field }) => (
<MaskedInput
mask="99/99"
maskChar=""
value={field.value}
onChange={field.onChange}
>
{(inputProps: any) => (
<input
{...inputProps}
type="text"
/>
)}
</MaskedInput>
)}
/>
This solution work for me.
You will need the following packages on your package.json:
"react-hook-form": "^7.34.0",
"#hookform/resolvers": "^2.9.7",
"react-input-mask": "^3.0.0-alpha.2",
"#types/react-input-mask": "^3.0.1",
You can install this version of react-input-mask with the comand ...
yarn add react-input-mask#next
yarn add #types/react-input-mask
Here is the code:
<InputMask
// mask options
mask={"99.999.999/9999-99"}
alwaysShowMask={false}
maskPlaceholder=''
// input options
type={'text'}
placeholder="Ex: 00.000.000/0000-00"
// react hook form register
{...register("cnpj", { required: true })}
/>
Mask format was wrong needed to be in something like this
mask="(+7 (999) 999-99-99)"
To help others
If you're using not controlled Input Fields (like native input), ou can use a function to mask the input
This cant be used with controlled input fields like (Material UI)
Example #component/input.tsx
import React from 'react'
import { Container, ErrorMessage } from './styles'
interface InputProps {
label?: string | true
defaultValue?: string
name?: string
type?: string
mask?: (value: string) => string
placeholder?: string
disabled?: boolean
error?: any
value?: string
register?: any
}
const Input: React.FC<InputProps> = ({
label,
defaultValue,
name,
type,
mask = (value: string) => value,
value,
placeholder,
disabled,
error,
register,
...inputProps
}) => {
return (
<Container>
{label && (
<label htmlFor={name}>
{(typeof label === 'string' && label) ||
placeholder ||
'Preencha este campo'}
</label>
)}
<input
onChange={e => (e.target.value = `${mask(e.target.value)}`)}
disabled={disabled}
ref={register}
id={name}
name={name}
type={type}
value={value}
placeholder={placeholder}
defaultValue={defaultValue}
{...inputProps}
/>
{error && <ErrorMessage>{error.message}</ErrorMessage>}
</Container>
)
}
export default Input
Usage example #page/form.tsx
function CPFMask(v: string): string {
v = v.replace(/\D/g, '')
v = v.replace(/^(\d{3})(\d)/g, '$1.$2')
v = v.replace(/^(\d{3})\.(\d{3})(\d)/, '$1.$2.$3')
v = v.replace(/^(\d{3})\.(\d{3})\.(\d{3})(\d)/, '$1.$2.$3-$4')
v = v.replace(/^(\d{3})\.(\d{3})\.(\d{3})\/(\d{2})(\d)/, '$1.$2.$3-$4')
return v.substring(0, 14)
}
...
<Input
type="text"
mask={CPFMask}
placeholder="CPF"
name="cpf"
label
register={register({
required: {
value: true,
message: 'CPF é obrigatório',
},
pattern: {
value: /([0-9]{2}[\.]?[0-9]{3}[\.]?[0-9]{3}[\/]?[0-9]{4}[-]?[0-9]{2})|([0-9]{3}[\.]?[0-9]{3}[\.]?[0-9]{3}[-]?[0-9]{2})/i,
message: 'CPF inválido',
},
})}
error={errors.cpf}
/>
...
Here's an example, wrap the children with a function, let's think of InputMask as Controller and children as render. So I put the ref prop on the children to redirect the ref errors directly to the children or render, not the Controller.
<InputMask name="npwp" mask="99.999.999.9-999.999">
{(inputProps) => (
<input
{...inputProps}
ref={register}
type="text"
placeholder="Input NPWP"
/>
)}
</InputMask>
This is how I did it without using register, and with a different masking library (s-yadav/react-number-format).
A work-around, as I could not get it to work with {...register()}.
<NumberFormat
type="tel"
defaultValue={formDefaultValue}
onValueChange={(values) => {
// Mirror the value for form validation
setFormValue("amount", values.value);
}}
customInput={(props) => {
return (
<Input
name="amount"
formatProps={props}
errors={formErrors}
/>
);
}}
/>
Inside Input component:
<input
{...(formatProps ? formatProps : {})}
/>

Resources