how to implement form for mapped child component - reactjs

I have a parent component that has the root <Form>. The child component has another fields which needs to be validated. But the the child component is mapped from a data and once i try to change one field, it changes every fields.
Code:
<Form id="myForm" name="basic" onFinish={onSubmit}>
<Form.Item
name="title"
rules={[
{
required: true,
message: "Please input your title!"
}
]}
>
<Text editable>{title}</Text>
</Form.Item>
{data.map((d) => (
<SecForm />
))}
</Form>
Child Component:
const SecForm = () => {
return (
<>
<Form.Item
label="target"
name="target"
rules={[
{
required: true,
message: "Please input your target!"
}
]}
>
<Input placeholder="Target" />
</Form.Item>
</>
);
};
Tried giving ids to the mapped component, but still dint work.
Any simpler solution is apreciated.
Code sandbox link: https://codesandbox.io/s/basic-antd-4-16-9-forked-o8nxdl?file=/index.js

I believe this happens because <SecForm> sets the same name to all form items. Try to pass the data to that component, and change the name of the item based on it
const SecForm = ({ data }) => {
return (
<>
<Form.Item
label="target"
name={`target${data}`}
rules={[
{
required: true,
message: "Please input your target!"
}
]}
>
<Input placeholder="Target" />
</Form.Item>
</>
);
};

Related

set initalValues in nested dynamic form | Antd

I've created the sandbox below hoping someone can help me.
https://codesandbox.io/s/suspicious-leaf-cijswt?file=/src/App.js
What I need to do is basically load the ingredients array as initialValues of Form.List.
Is that possible? If yes, how?
I'd really appreciate any help.
Thanks!
Use initialValues prop in Form to initialize fields. Since you named your FormList as users. You can set the values like this:
initialValues={{ users: ingredients }}
Now your field looks like this:
<Form.Item
{...restField}
name={[name, "first"]}
rules={[{ required: true, message: "Missing first name" }]}
>
<Input placeholder="First Name" />
</Form.Item>
The most thing is the name attribute name={[name, "first"]}. In ingredients array, each object have the following keys: key, id, & amount. Suppose you want to show id & amount in each input. You specify the field path using [name, "id"]. where name presents the index of array & id is the key of object in an array. Antd will automatically get the value if it's available in that array.
I just make few changes changes like proper naming keys,... according to the data
Complete Code
import { Form, Input, Button, Space, InputNumber } from 'antd';
import { MinusCircleOutlined, PlusOutlined } from '#ant-design/icons';
const ingredients = [
{
key: 0,
name: 'Wheat Flour',
amount: 1000
},
{
key: 1,
name: 'Sugar',
amount: 800
}
];
export default function App() {
return (
<Space style={{ display: 'flex', margin: 36 }} align='baseline'>
<Form
name='dynamic_form_nest_item'
onFinish={console.log}
autoComplete='off'
initialValues={{ ingredients: ingredients }}
>
<Form.List name='ingredients'>
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, ...restField }) => (
<Space key={key} style={{ display: 'flex', marginBottom: 8 }} align='baseline'>
<Form.Item
{...restField}
name={[name, 'name']}
rules={[{ required: true, message: 'Missing ingredient' }]}
>
<Input placeholder='Ingredient' />
</Form.Item>
<Form.Item
{...restField}
name={[name, 'amount']}
rules={[{ required: true, message: 'Missing Amount' }]}
>
<InputNumber placeholder='Amount' />
</Form.Item>
<MinusCircleOutlined onClick={() => remove(name)} />
</Space>
))}
<Form.Item>
<Button type='dashed' onClick={() => add()} block icon={<PlusOutlined />}>
Add field
</Button>
</Form.Item>
</>
)}
</Form.List>
<Form.Item>
<Button type='primary' htmlType='submit'>
Submit
</Button>
</Form.Item>
</Form>
</Space>
);
}

How to get error message by getFieldError in AntD Form?

I'm validating form with Ant Design but I have a problem with getFieldError(). I need to get the error messages by the field name of Form.Item but it not works.
Here's my code not works below:
...
<Form form={form} name="login_form" onFinish={onFinish} scrollToFirstError>
<Form.Item
label="Password"
name="password"
rules={[
{
required: true,
message: 'Password cannot be empty!',
},
]}
help='' // hide validating message.
>
<>
{({ getFieldError }) => console.log(getFieldError('password'))}
//it not logging anything when submit form trigger error
<Input.Password placeholder="Enter your password" />
</>
</Form.Item>
</Form>
How can I solved this problem?
Your console.log will invoke, every time your component renders, so you need to rerender your component whenever validation applies on the form. To handle this situation you can use render prop with Form component, like this:
function CustomFormItem({ error, ...other }) {
console.log(error)
return <Input.Password placeholder="Enter your password" {...other} />;
}
function MyForm() {
const [form] = Form.useForm();
const onFinish = (values) => {
console.log(values);
};
return (
<Form
form={form}
name="login_form"
onFinish={onFinish}
scrollToFirstError
>
{(values,formInstance) => {
return (
<>
<Form.Item
label="Password"
name="password"
rules={[
{
required: true,
message: 'Password cannot be empty!',
},
]}
help="" // hide validating message.
>
<CustomFormItem error={formInstance.getFieldError('password')} />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</>
);
}}
</Form>
);
}
Consider that with above implementation, render prop will call with every change on the form.
Use can use getFieldError(); like the code example below
Function as Child Component is not working perfectly inside <Form.Item> component as of now.
<Form {...layout} form={form} name="control-hooks" onFinish={onFinish}>
{(values, formInstance) => {
console.log(formInstance.getFieldError("password")[0]);
return (
<>
<Form.Item
name="password"
label="Password"
rules={[
{
required: true
}
]}
>
<Input />
</Form.Item>
</>
);
}}
</Form>

using ant design switch inside Forms

What's the correct way to use ant design switch inside, I could not get much from the official documentation.
Switch-Ant Design
Here's how I am using it.
<Form form={form} layout="vertical">
<Form.Item
label="Description"
name="description"
rules={[{ required: true, message: 'Enter a description' }]}
>
<Input placeholder="Enter Description" />
</Form.Item>
<Form.Item name="switch" noStyle valuePropName="checked">
<Switch checkedChildren="Yes" unCheckedChildren="No" />
<span>Chargable</span>
</Form.Item>
<Button
onClick={() => {
form
.validateFields()
.then((values) => {
form.resetFields()
onCreate(values)
})
.catch((info) => {
console.log('Validate Failed:', info)
})
}}
>
Save
</Button>
</Form>
onCreate does no take the value from the switch, It does take it from the description
const onCreate = (values) => {}
I was able to fix it but doing the following.
<td>
<Form.Item valuePropName="checked" name="status" noStyle>
<Switch checkedChildren="Yes" unCheckedChildren="No" />
</Form.Item>
<span className="ml-2">Status Enabled</span>
</td>
I guess your values are {description: "foo", switch: undefined}?
In my demo, switch demo, I add initialValue to Switch, so when I get values from the form, I get {description: "111", switch: true}.
I don't know whether this is what your mean.
or you can use like this
<Form.Item label="foo">
<Form.Item name="bar">
<Switch />
</Form.Item>
<span className="ant-form-text">Some text you want</span>
</Form.Item>
This is because you must only have one child inside a Form.Item component. Remove the span besides your Switch component and it will work.

Display an error if the password and login are incorrect in Form. Antd React

The task is as follows, when you press the LOGIN button, a request is sent to the server with a password and login, if they are incorrect, then under the password entry line you need to display the corresponding error and all input fields should be highlighted in red.
How can you achieve this?
I tried to do it for a very long time using built-in validators in Form.Item . So, since I don't need to worry about changing the color of input fields, the validator does it itself, but I got confused about these validators and I got an infinite loop.
Here is some of the code for the Login page.
export const LoginPage = () => {
const { dispatch } = useAuthContext()
const onFinish = (values: any) => {
APIs.requestLogin(values.username, values.password, false)
.then((response: any) => {
dispatch({ type: SIGN_IN, payload: response.data })
})
.catch(() => {
console.log('error')
})
}
return (
<div className={classes.root}>
<div className={classes.container}>
<Form
className={classes.form_container}
name="normal_login"
initialValues={{ remember: true }}
onFinish={onFinish}
>
<Form.Item
className={classes.form_input}
name="username"
rules={[{ required: true, message: 'Please enter your username!' }]}
>
<Input
autoFocus={true}
className={classes.input_style}
placeholder="Username"
prefix={<UserOutlined className="site-form-item-icon" />}
/>
</Form.Item>
<Form.Item
className={classes.form_input}
name="password"
rules={[{ required: true, message: 'Please enter your password!' }]}
>
<Input.Password className={classes.input_style} placeholder="Password" prefix={<LockOutlined />} />
</Form.Item>
<Form.Item className={classes.form_submit}>
<Button className={classes.form_button_submit} type="primary" htmlType="submit">
LOGIN
</Button>
</Form.Item>
</Form>
<div className={classes.image} />
</div>
</div>
)
}

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