How to custom value of Form Field in AntD? - reactjs

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

Related

Antd TypeScript : Log data when user clicks enter

In the project I'm working, I have wrapped the input around a form, and the idea is when the user types something and clicks enter, the data is logged. But the issue is I'm not getting such logs.
Here is my code :
Index.tsx
const onFinish = (values: any) => {
console.log("yoyo");
console.log(values);
};
<Form name="control-ref" onMouseEnter={onFinish}>
<Form.Item name="note" rules={[{ required: true }]}>
<InputField
variant="search"
placeholder="Search"
addonAfter={selectAfter}
className="search-field"
/>
</Form.Item>
</Form>
The InputField with the specified variant returns this components
const SearchField: React.FC<IInputFieldProps> = (props) => {
const { placeholder } = props;
return (
<Input
className="search-field"
placeholder={placeholder || 'Search'}
{...props}
/>
);
};
Please help
Log the data when the form is submitted. Forms can be submitted by pressing enter.
<Form name="control-ref" onFinish={(values: any) => {
console.log("yoyo");
console.log(values);
}}>
{...}
</Form>
Edit: updated submission callback according to ant design react docs

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.

React state sets the same value to all of the state values

I'm new to react JS, I'm trying to get the values from a form, and send it to a node JS middleware.
I set up two values in the state, one for the email and another one for the password. I set the state for both values in the set state method.
class LoginForm extends Component {
constructor(props){
super(props)
this.state = {
email : '',
password : '',
}
}
handleChange = (e) => {
this.setState({ email : e.target.value, password : e.target.value})
}
handleSubmit = (e) => {
console.log('state', this.state)
};
render () {
return (
<div style = {styles.form} >
<Fragment>
<Form
{...layout}
name="basic"
initialValues={{
remember: true,
}}
onFinish={this.handleSubmit}
>
<Form.Item
name="email"
rules={[
{
type: 'email',
message: 'The input is not valid E-mail!',
},
{
required: true,
message: 'Please input your E-mail!',
},
]}
hasFeedback
>
<Input
placeholder={t`Email`}
value={this.state.email}
onChange={this.handleChange} />
</Form.Item>
<Form.Item
name="password"
rules={[{ required: true }]} hasFeedback
>
<Input.Password
placeholder={t`Password`}
value={this.state.password}
onChange={this.handleChange}
/>
</Form.Item>
<Button
type="primary"
htmlType="submit"
>
<span style = {styles.button} >Sign in</span>
</Button>
</Form>
</Fragment>
</div>
)
}
}
}
I created the handle submit function and linked it to the onsubmit method inside the form and tried console logging the current state of my values inside the handle submit function. To my surprise the value from the password gets console logged for the value email too. Like this
state {email: "123", password: "123"}
I cannot figure out what am I doing wrong.
I think if you change your handleChange function to this, it should work.
handleChange = (e) => {
this.setState({ [e.target.id] : e.target.value})
}
And add id to the input fields like this
<Input id="email" placeholder={t`Email`} value={this.state.email} onChange {this.handleChange} />
<Input.Password id="password" placeholder={t`Password`} value {this.state.password} onChange={this.handleChange} />
Here is the solution:
handleChange = (e) => {
let email = ''
let password = ''
if (e.target.name === 'email') {
email = e.taget.value
} else {
password = e.taget.value
}
this.setState({ email, password})
}

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

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
}

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