How to get data from form component and pass to method in React? - reactjs

In a React project, I have form component which gets input data like email, password and passes to submit method. In a method 'requestOTP' requires email from form component. What could be appropriate solution to get that email data from form and pass to requestOTP method? Below is the code for reference.
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
control={control}
name="email"
render={({ onChange, value, ref }) => (
<Input
placeholder="EMAIL"
onChange={onChange}
ref={ref}
value={value}
type="email"
/>
)}
rules={{
required: "Please enter email",
pattern: {
value: /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,}$/i,
message: "Invalid email address"
}
}}
/>
<div className={classes2.root}>
<Button
variant="contained"
type="submit"
>
LOG IN
</Button>
</div>
</form>
<form onSubmit={handleSubmit(requestOtp)}>
<Button
variant="contained"
type="submit"
>
GET AN OTP ON YOUR EMAIL
</Button>
</form>
const requestOtp = async (data) => {
{/* I want email data from form component here */}
}

onSubmit event listener already have target values. For example, If you have input tag named 'email' in your form (that is <input name="email" ... />)
function handleSubmit(e) {
const email = e.target['email'].value;
//... and then pass email to the requestOTP function
}

Related

Validation for Input form component React

I have a form component that include multiple TextFields and each one have different validation and error. Assume my TextField had custom validation prop that will take some conditions and show validation either onChange or onBlur for each TextField. I also have custom error prop that display message without condition.
const Address = ({
onChange,
required,
error,
value = {},
validation = undefined,
}: AddressProps) => {
const validator = {
validationAddress: (value: string) => (value.length === 0) ? 'Address is required' : '',
validationCity: (value: string) => (value.length === 0) ? 'City is required' : '',
}
const handleChange = (event) => {
...
}
return (
<React.Fragment>
<TextField
id="address"
label="address"
type="text"
required={required}
onChange={handleChange}
value={value.address}
validationEvent="change"
validation={validator.validationAddress}
/>
<TextField
id="city"
label="city"
type="text"
required={required}
onChange={handleChange}
value={value.city}
validationEvent="change"
validation={validator.validationCity}
/>
</React.Fragment>
export default Address;
After that I will implement my Address component in an App with submit button.
const App = () => {
const handleSubmit = () => {
...
}
return (
<Address />
<button type='submit' onClick={handleSubmit}>
Submit
</button>
)
}
export default App;
I saw many examples that input and form put together with submit button but I am struggling with handle them separately this way. My task is need to handle validation in Address component but have submit button as an optional option outside the Address component. My goal is validation message should not show until Submit button is clicked.
Try this:
move validator to parent component
pass validatorMessage useState var to Address component
call the validator by the click of submit button
Now the message is managed in the parent component and you control when the submit button displays it.
I would suggest to consider a different approach: there is no need to manually implement validation, we can use the browser built-in validation feature:
https://medium.com/p/491327f985d0
Essentially I use standard HTML mark-up and properties.
Implementation example:
export default function App() {
const onSubmit = (data: FormData) => {
console.log(Object.fromEntries(data.entries()));
};
return (
<div className="App">
<Form onSubmit={onSubmit}>
<h2>A simple form</h2>
<TextInput label="Name:" id="name" name="name" required />
<TextInput
label="Email:"
id="email"
type="email"
name="email"
required
/>
<TextInput label="Address:" id="address" name="address" />
<TextInput
label="Tel:"
id="tel"
name="tel"
type="tel"
pattern="((\+44(\s\(0\)\s|\s0\s|\s)?)|0)7\d{3}(\s)?\d{6}" // don't rely on this
/>
<button>Submit</button>
</Form>
</div>
);
}
The Form component itself is very simple:
<form
action={action}
onSubmit={handleSubmit}
noValidate
className={style.form}
>
<div className={style.wrapper}>{children}</div>
</form>
It sets the noValidate attribute to prevent the default error notification to pop up.
The input boxes are wrapped in the form element.
The form element has an onSubmit event handler: it gets triggered when user clicks on the submit button OR when the user hit return using the keyboard.
At that point we use e.preventDefault(); to prevent default form submission and handle it manually.

How to custom value of Form Field in AntD?

I am handling Form.Item with Ant Design, everything works fine, however I want to custom the value of Form.Item like below code example:
const onFinish = (values) => {
console.log('Values received:', values);
/*
Normally we would get the result like:
{
email: 'abc#gmail.com'
}
===================================================
But as expected, when user input an email
i want to get the result directly with object format like this:
{
email: { email: 'abc#gmail.com', rule: 'user' }
}
*/
};
return (
<Form
name="user_information"
onFinish={onFinish}
>
<Form.Item
label="Email"
name="email"
rules={[
{
required: true,
message: 'Your email cannot be empty!',
},
]}
>
<Input placeholder="Enter your email" />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Update now
</Button>
</Form.Item>
</Form>
);
I tried providing value prop to <Input /> component but it not works.
So what does I need to provide to Form.Itemor Input to solve the above problem?
Thanks!
Antd Form gives us the values when submitting the form of all the form control inputs in the form of the object where the key would be the name of the form control inputs and value would be the value given by the user.
The best practice which I know about is that we should never change the input values before submitting the form manually otherwise our form may show unexpected behavior which we can't figure out.
However, if you want to do a post request with a payload of data that is slightly different than the form values, then you can modify the form data before submitting the request.
const [formValues, setFormValues] = useState()
const onFinish = (values) => {
console.log("Values received:", values);
// modify the form value here
// remember don't change `values`, preserve the form value in some other variable or state.
const keys = Object.keys(changedValues);
let newValues = { [keys[0]]: { [keys[0]]: changedValues[keys[0]]} }
console.log(newValues);
};
return (
<Form name="user_information" onFinish={onFinish}>
<Form.Item
label="Email"
name="email"
rules={[
{
required: true,
message: "Your email cannot be empty!",
},
]}
>
<Input placeholder="Enter your email" />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Update now
</Button>
</Form.Item>
</Form>
);

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>
);

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

Submitting redux form values

I am new to react and redux technology. now started building an application that contains several redux forms. We want to submit simple form with values.
For ex: login form
Username : text input field
Password: text input field
Submit button
After entering values in fields and click on submit button i want to get the username and password field values in object or json data .. so that I can store it to my server with POST method.
Right now we are using handleSubmit(), but data is not coming as object
1 - The best practice to deal with input values are making them controlled. Which means :
Instead of
<input type='password' />
You do :
<input
type='password'
value={password}
onChange={ event => myInputHandler( event.target.value ) }
/>
The value might come from your state, redux state or as a props etc.
Your handler function differs according to where you store it.
I will give you an example with react state :
<input
type='password'
value={this.state.password}
onChange={ event => this.setState({ password : event.target.value }) }
/>
So whenever someone types, your onChange handler will be called, so that your react state will update with the input ( event.target.value ).
2 - If you need these values when a user submits, then you need to wrap these input fields within a form element and attach a onSubmit handler.
onSubmitHandler( event ){
event.preventDefault()
let password = this.state.password
// use password or other input fields, send to server etc.
}
<form onSubmit={ event => this.onSubmitHandler(event) }>
<input
type='password'
value={this.state.password}
onChange={ event => this.setState({ password : event.target.value }) }
/>
</form>
Hope you get what you need.
If you are using redux to store state then use redux-from then use redux from
import React from 'react'
import {Field, reduxForm} from 'redux-form'
const SimpleForm = props => {
const {handleSubmit, submitting} = props return (
<form onSubmit={handleSubmit(e=>console.log('your form detail here', e))}>
<div>
<label>First Name</label>
<div>
<Field name="firstName" component="input" type="text" placeholder="First Name" />
</div>
</div>
<div>
<label>Last Name</label>
<div>
<Field name="lastName" component="input" type="text" placeholder="Last Name" />
</div>
</div>
<div>
<button type="submit" disabled={pristine || submitting}>Submit</button>
</div>
</form>
) }
export default reduxForm({ form: 'simple'})(SimpleForm)
Go here for more detail
https://redux-form.com
I put the name of the input as the key that I want to use.
Then each time the input changes I destructure the event passed to the onChange function, and I use the name,value to update the state.
On form submit make sure to use preventDefault(); in order to avoid the page refreshing.
import React, { Component } from 'react'
class FormExample extends Component {
constructor(props){
super(props)
this.state = {
formData: {}
}
}
handleInputChange = ({ target: { name,value } }) => {
this.setState({
formData: {
...this.state.formData,
[name]: value
}
})
}
handleFormSubmit = e => {
e.preventDefault()
// This is your object
console.log(this.state.formData)
}
render() {
return(
<div>
<Form
handleSubmit={this.handleFormSubmit}
handleChange={this.handleInputChange}
/>
</div>
)
}
}
const Form = ({ handleSubmit, handleChange }) => (
<form onSubmit={handleSubmit}>
<input onChange={handleChange} name="username" type="text" placeholder="Username" />
<input onChange={handleChange} name="password" type="password" placeholder="Password" />
<button>Submit</button>
</form>
)
export default FormExample

Resources