React Hook Form controller extract variables - reactjs

I have some questions about the react-hook-form controller
https://react-hook-form.com/api/usecontroller/controller
At the moment it looks like this:
<Controller
name="password"
defaultValue=""
rules={{ validate: value => isPasswordValid(value) || 'Does not match criteria' }}
control={control}
render={({ field: { value, onChange } }) => (
<PasswordTextField
error={!!errors.password}
label="Your password"
variant="standard"
value={value}
inputProps={{ role: 'password' }}
InputProps={{
onChange,
onBlur: () => setFocus(!!password),
onFocus: () => setFocus(true),
}}
/>
)}
/>
How do I extract variables that I want to use elsewhere?
Goal is to check if the password input field is empty..

Ok I got this!
You have to import:
import classNames from 'classnames';
and surround your password field with:
className={classNames(classes.passwordField, { [classes.passwordFieldActive]: password.length })}
It's a pretty individual case here to be honest, but maybe in your case you probably also extract the password, so you can check if there's a password.length -> truthy

Related

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>
)}
/>

How can I set validation rules when all fields are empty React Hook Form

I'm using React Hook Form V7. I have two input fileds and using Controller to control the input.
The below one is what I did now, each field is required.
<form onSubmit={handleSubmit((data) => console.log(data))}>
<Controller
render={({ field }) => <TextField value={field.value} onChange={field.onChange} />}
name="test1"
control={control}
rules={{ required: true }}
/>
<Controller
render={({ field }) => <TextField value={field.value} onChange={field.onChange} />}
name="test2"
control={control}
rules={{ required: true }}
/>
<input type="submit" />
</form>
My question is how can I set instead of each one is required, I want the error message showing when both fields are empty, if only one is empty is accepted.
Is there any onSubmit validation on React Hook Form? Or I need to do the normal validation on the onSubmit function to check the value then set if error message show?
Edit:
this is what I did now:
const [submitError, setSubmitError] = useState(false)
onSubmit((data) => {
const { test1, test2 } = data
if (!test1 && !test2) {
setSubmitError(true)
} else {
setSubmitError(false)
// do submit action
}
})
const errorEmptyMessage = "one of test1 and test2 should has value"
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
render={({ field }) => <TextField value={field.value} onChange={field.onChange} />}
name="test1"
control={control}
rules={{ required: true }}
/>
<Controller
render={({ field }) => <TextField value={field.value} onChange={field.onChange} />}
name="test2"
control={control}
rules={{ required: true }}
/>
{submitError && emptyMessage}
<input type="submit" />
</form>
)
I wonder if React Hook Form has a built-in function to do this?
Is there any onSubmit validation on React Hook Form? Or I need to do
the normal validation on the onSubmit function to check the value then
set if error message show?
Yes, You have a nice solution which I recommend it to use nested of normal validation, its name schema validation like YUP, Simply what you need to do is add needed rule, for example (from react-hook-form):
import React from "react";
import { useForm } from "react-hook-form";
import { yupResolver } from '#hookform/resolvers/yup';
import * as yup from "yup";
const schema = yup.object({
firstName: yup.string().required(),
age: yup.number().positive().integer().required(),
}).required();
export default function App() {
const { register, handleSubmit, formState:{ errors } } = useForm({
resolver: yupResolver(schema)
});
const onSubmit = data => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("firstName")} />
<p>{errors.firstName?.message}</p>
<input {...register("age")} />
<p>{errors.age?.message}</p>
<input type="submit" />
</form>
);
}
If you read the above code, you see you are build a schema for each field needed, and you have a lot of options, for example in your case you may use when to handling on x and y is empty and so on..., also you have a lot of validation schema build as an object like int, min and required, you can check this part.
Also you can do that via onSubmit on normal flow, like this:
const onSubmit = () => {
throw new Error('Something is wrong')
}
handleSubmit(onSubmit).catch((e) => {
// you will need to catch that error
})
and the idea here you check what you need and you can throw the error, exampe:
const { register, handleSubmit } = useForm();
const onSubmit = (data, e) => console.log(data, e);
const onError = (errors, e) => console.log(errors, e);
return (
<form onSubmit={handleSubmit(onSubmit, onError)}>
<input {...register("firstName")} />
<input {...register("lastName")} />
<button type="submit">Submit</button>
</form>
);
But from my side, I suggest to use schema validation, its really useful base on my experience with react hook form.
Update 1: More Example:
In above is example how you can build conditions to resolve issue, but simply visit yup and check when,
const schema =
object().shape({
a: string().when(["a", "b"], {
is: (a, b) => !a && !b
then: string().required("At least one is to be selected"),
otherwise: string() // unnecessary
}),
a: string().when(["a", "b"], {
is: (a, b) => !a && !b
then: string().required("At least one is to be selected"),
otherwise: string() // unnecessary
})
});

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.

why is first letter dead in react-hook-form input

i need help to understand why the first letter in the simple input component is not registered.
I've created a simple controlled input from the examples but its not working properly.
i created an example for you https://stackblitz.com/edit/react-9zezqx
const App = () => {
const { register, handleSubmit, watch, errors, reset, control, formState } = useForm({ mode: 'onChange' });
console.log(errors)
return (
<div>
<form onSubmit={handleSubmit(() => console.log("submit"))}>
<Controller
as={TextInput}
name="firstname"
defaultValue=""
control={control}
inputRef={register({ required: true, minLength: 8 })}
hasErrors={errors.firstname !== undefined}
/>
<br/>
<Controller
as={TextInput}
name="hobby"
defaultValue=""
control={control}
inputRef={register({ required: true, minLength: 8 })}
hasErrors={errors.hobby !== undefined}
/>
</form>
</div>
);
}
render(<App />, document.getElementById('root'));
import * as React from 'react';
export const TextInput = (props) => {
return(
<>
<input
type="text"
name={props.name}
value={props.value}
onChange={props.onChange}
ref={props.inputRef}
/>
{props.hasErrors && (<h2>errors!!</h2>)}
</>
)
}
okay i found the bug causing it in 'onBlur' aswell
reValidateMode: 'onBlur'
Swap the mode to onBlur, this will improve the performance, will trigger only when the user leaves the field, which is suppose to happen, and also does not swallow the first input.
onChange skips the first letter, because the default value will be used for the initial onChange call, which is empty.
You are probably using an uncontrolled input. If that's the case use defaultValue instead of value.
Reference
This is the problem here, you are try to use Controller with register:
https://react-hook-form.com/api#Controller
<Controller
as={TextInput}
name="hobby"
defaultValue=""
control={control}
/>
or
https://react-hook-form.com/api#register
<TextInput inputRef={register} />

Resources