Using bootstrap components with react-hook validation form - reactjs

I've been working with React for a while, and decided to try out react-hook. I'm trying to make a simple form with some simple validation, but it seems like the validation does not apply to bootstrap components. For the 'regular' input, it works fine, but for the form.control it's not working(The validation is skipped). Saw one solution where you wrap the componenet in a controller, as shown bellow, but i got the same result. Any ideas?
Thanks.
function Example(){
const { register, handleSubmit, control, errors } = useForm();
const onSubmit = (data:any) => {
console.log(data)
}
return(
<Form onSubmit={handleSubmit(onSubmit)}>
<Form.Label column>Name</Form.Label>
<Controller as={<Form.Control/>} name="firstName" control={control} ref={register({required: true})} defaultValue="" />
{errors.firstName && <p>This is required</p>}
<input name="lastName" className="form-control" ref={register({required: true})} />
{errors.lastName && <p>This is required</p>}
<input type="submit" ref={register({required: true})}/>
</Form>
)
}

Related

React Controlled Input Validation

I noticed a weird behavior where controlled components are not respecting the minLength and allowing a form to submit even though that condition is not met.
Validation works fine for uncontrolled components.
What is the reason for this behavior?
export default function App() {
const [uncontrolledSubmitCount, setUncontrolledSubmitCount] = useState(0);
const [controlledSubmitCount, setControlledSubmitCount] = useState(0);
const [content, setContent] = useState("");
return (
<div className="App">
<h2>Uncontrolled (minLength: 10)</h2>
<form
onSubmit={(e) => {
console.log(e);
e.preventDefault();
setUncontrolledSubmitCount(uncontrolledSubmitCount + 1);
}}
>
<textarea
type="text"
minLength={10}
maxLength={30}
required
/>
<br />
<button type="submit">Submit</button>
<br />
<span>Submit Count: {uncontrolledSubmitCount}</span>
</form>
<h2>Controlled (minLength: 10)</h2>
<form
onSubmit={(e) => {
console.log(e);
e.preventDefault();
setControlledSubmitCount(controlledSubmitCount + 1);
}}
>
<textarea
type="text"
minLength={10}
maxLength={30}
required
value={content}
onChange={(e) => setContent(e.currentTarget.value)}
/>
<br />
<button type="submit">Submit</button>
</form>
<span>Submit Count: {controlledSubmitCount}</span>
</div>
);
}
Here's a reproduction link:
https://codesandbox.io/s/kind-violet-zwcct?file=/src/App.js
This behavior happens only on Chrome as far as I tested it.
Based on React official documentation adding value to textarea it overrides HTML validations and it makes it "controlled" input and it ignores it overall. But only in Chrome.
The documentation also says there is an option to use defaultValue. I tried it at it works.
<textarea
minLength={10}
maxLength={30}
required
defaultValue=""
onChange={(e) => setContent(e.currentTarget.value)}
/>
Working example from your codesanbox
With this solution you will solve Chrome problem but still keep content state with value that you enter inside textarea
NOTE:
If you try to use children value, React will throw an error that it is not supported for controlled textarea

react-hook-form can't see change value by click on button to reset input

Component with input and button to reset input TexInputComponent:
<input
type={type}
name={name}
ref={register}
/>
<button
type="button"
onClick={clearInput}>
Reset input
</button>
const clearInput = () => {
document.querySelector(`#${name}`).value = null;
};
I'm using TexInputComponent inside form in another component:
<TexInputComponent
name="title"
defaultValue={data?.title}
register={register({ required: 'Title is required.' })}
error={errors.title}
/>
Now when I click submit on form react-hook-form return me error e.g 'Title is required!'. When I writing something in TexInputComponent, then error disapear.
The problem is when I writing text and click button to reset input. The clearInput method is executed (this method changing value to null) Now should displaying error, but I thing the react hook form can't see value changing.
How I can fix it?
Your clearInput() doesn't work because you don't provide a unique id so it can't find the input element to reset. So change to this:
<input
id={name} // --> add this line to fix
type={type}
name={name}
ref={register}
/>
However there are other ways to easily reset the form without having to define your own reset method:
Use <input type='reset' /> to create a reset button that resets all fields in a form.
Use reset() function from useForm hook to reset a specific field:
const { register, reset } = useForm();
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label>First name</label>
<input type="text" name="firstName" ref={register} />
<label>Last name</label>
<input type="text" name="lastName" ref={register} />
<input type="submit" />
<button
type="button"
onClick={() => reset({ firstName: "default name" })}
>
Reset first name
</button>
</form>
);

React Hook Form problem with validating using validate function

Hey I'm currently working on validation using customized Antd inputs and React Hook Form.
Currently I have problem with validating fields for URLs (single url and image one) with regex.
I've checked both of regex and they are working
Generally I can't submit the form with correct data, the problem happens within the validation using regex
The form part
<Controller
as={
<InputField
label="URL"
name="url"
placeholder="Enter URL"
error={errors.url}
errorText="URL Error"
/>
}
control={control}
type="text"
name="url"
defaultValue=""
rules={{
validate: (value) => {
return INPUT.urlPattern.test(value);
}
}}
/>
<Controller
as={
<InputField
label="Image Url"
name="imageUrl"
placeholder="enter ImageURL"
error={errors.imageUrl}
errorText="Error on imageUrl"
/>
}
control={control}
type="text"
name="imageUrl"
defaultValue=""
rules={{
validate: (value) => {
return INPUT.imageURLPattern.test(value);
}
}}
/>
Custom antd input component render function
return (
<>
<label className="label" htmlFor={name}>
{label}
</label>
<Styled.Input
placeholder={placeholder}
maxLength={maxLength}
value={value}
onChange={handleInputCounter}
{...(counter
? {
suffix: (
<Styled.WordCounter>
{counterValue} / {maxLength}
</Styled.WordCounter>
)
}
: {})}
/>
{error && <p className="error">{errorText}</p>}
</>
);
I've prepared little demo on codesandbox
https://codesandbox.io/s/react-hook-form-validate-antd-gyhnh?file=/src/EntryForm.tsx

Specify initial value for radio button

I want to the "Exact" radio button to be checked when a form is opened:
<Form
onSubmit={onSubmit}
initialValues={{ match_type: "exact" }}
render={({ handleSubmit, form, reset, submitting, pristine, values }) => (
<form
onSubmit={() => {
handleSubmit();
}}
>
<fieldset>
<legend>Match type</legend>
<Field name="match_type">
{({ input }) => (
<label>
<input {...input} type="radio" value="fuzzy" /> Fuzzy
</label>
)}
</Field>
<Field name="match_type">
{({ input }) => (
<label>
<input {...input} type="radio" value="exact" /> Exact
</label>
)}
</Field>
</fieldset>
<button type="submit">Save match</button>
</form>
)}
/>
The radio button remains unchecked. Any idea how I should get this to work? Note using <Field component="input" type="radio" .../> is not an option for me.
Codesandbox: https://codesandbox.io/s/react-final-form-reset-after-submit-forked-q6jyv?file=/index.js:359-1235
You can set the default to be checked in the tag.
<input {...input} type="radio" value="exact" checked />
I just needed to use the Field component properly:
<Field name="match_type" type="radio" value="fuzzy">
{({ input }) => (
<label>
<input {...input} /> Fuzzy
</label>
)}
</Field>
This way the <input will get what it needs spread in from the argument to the render prop.
If you inspect your component in codesandbox provided, you can see that Field component doesn't have value prop. I'm attaching a screenshot here
You have a few options to solve this. The main idea though is to understand what you are passing when you say {...input} In your Field component, you currently only have name prop, so you can add something like this
input={{ name: 'match_type', value: 'exact', onChange: (e) => (whatever you need on change) }}
RFF could be tricky with just setting value like that since source of truth lives in the form. So, you can also use a mutator functionality of the form. This is a good description of how to do it

Other validation message is triggering instead of my message when using Ant design getFieldDecorator

I am using Ant design and this is my form when I click on save I am getting this type of validation msg instead of red bordered Antd validation msg
I want validation error like this which is shown in AntD documents.
https://codesandbox.io/s/do52z
I have writter my function like this
<Form id="myForm" onSubmit={this.handleSubmit}>
<Form.Item label="Code">
<CustomInput
form={this.props.form}
type="text"
disabled={this.state.disableFields}
name="code"
id="code"
placeholder=""
required={true}
errorMsg={"Please input code!"}
/>
</Form.Item>
</Form>
This is my custom Input
const CustomInput = ({
form, id, name, placeholder, required, errorMsg, type, disabled,}: Props) => {
return form.getFieldDecorator(id, {
rules: [
{
required: required,
message: errorMsg
}
]
})(
<Input
type={type}
name={name}
id={id}
disabled={disabled}
placeholder={placeholder}
className={name === "code" ? "code-input" : "input-box"}
/>
);
};
export default CustomInput;
and this is my save button
<Button
className="save-btn"
htmlType="submit"
form="myForm"
>
Save
</Button>
I think I am missing something little here. Thanks in advance
Ant design input doesn't have required prop..
Required prop should be give inside form.item rules prop.
Since you have given reqired to input tag it will cause Chrome to display a prompt that the user to fill out the field.
Update based on comment
Move formitem tag inside custominput component and try again.
<Form id="myForm" onSubmit={this.handleSubmit}>
<CustomInput
form={this.props.form}
type="text"
disabled={this.state.disableFields}
name="code"
id="code"
placeholder=""
required={true}
errorMsg={"Please input code!"}
/>
</Form>
..
const CustomInput = ({
form, id, name, placeholder, required, errorMsg, type, disabled,}: Props) => {
return(
<Form.Item label="Code">
{form.getFieldDecorator(id, {
rules: [
{
required: required,
message: errorMsg
}
]
})(
<Input
type={type}
name={name}
id={id}
disabled={disabled}
placeholder={placeholder}
className={name === "code" ? "code-input" : "input-box"}
/>
)}
</Form.Item>
)
};

Resources