Antd form: passing dynamic id alongside form-values - reactjs

im working on a commenting system. Every ID has some comments. If I want to make a new comment, the ID has to be passed alongside the form-values.
ID is being rendered dynamically:
{data && data.formations.map(formation =>
<Row>
<Col span={2}>
<p>ID: {formation.id}</p>
</Col>
...
Form has a Textarea, and the value is being passed automatically due the name prop in Form.Item.
<Form onFinish={onFinish}>
<Form.Item name="comment">
<TextArea rows={4} />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">Add comment</Button>
</Form.Item>
</Form>
Idealy, I want the ID passed alongside the values in the following function OnFinish:
const onFinish = (values) *id somehwere here* => {
console.log(values)
}
How to achieve this? Thanks in advance!

You could solve this by adding an hidden field which holds the ID :
<Form onFinish={onFinish}>
<Form.Item name="comment">
<TextArea rows={4} />
</Form.Item>
<Form.Item name="id">
<Input type="hidden" value={formation.id} />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">Add comment</Button>
</Form.Item>
</Form>
Then in the onFinish callback you should get a new property id in the values object.
This is the common way to pass known/readonly values alongside form values (in the non SPA / synchronous web world, eg PHP).

Related

Inputs not updating state in functional react component

I looked around and I see similar questions, but whenever I follow the answers I can't seem to get this to work in the way that I have it written. I am starting off all four states as blank inside of an array, but I want to update the states as the user types for each input field. Why is setChanging not working to update the state for the particular name of the input field? Console logs both the x and y values as I type into each input. I must be doing something simple wrong, but I can't figure out what it is.
const ContactForm = () => {
const initialValues = {
recipientName: "",
recipientEmail: "",
fromName: "",
fromEmail: "",
};
const [changing, setChanging] = useState(initialValues);
const handleInputChange = (e) => {
let x = e.target.name;
let y = e.target.value;
console.log(x);
console.log(y);
setChanging({...changing, [e.target.name]: e.target.value});
console.log(initialValues);
}
return (
<Form>
<Form.Group className="mb-3">
<Row>
<Col>
<Form.Control
type="text"
required
name="recipientName"
placeholder="Recipient Name*"
id="form.recipientName"
onChange={handleInputChange}
/>
</Col>
<Col>
<Form.Control
type="email"
required
name="recipientEmail"
placeholder="Recipient Email*"
id="form.recipientEmail"
onChange={handleInputChange}
/>
</Col>
</Row>
</Form.Group>
<Form.Group className="mb-3">
<Row>
<Col>
<Form.Control
type="text"
required
name="fromName"
placeholder="From Name*"
aria-invalid="form.fromName"
onChange={handleInputChange}
/>
</Col>
<Col>
<Form.Control
type="email"
required
name="fromEmail"
placeholder="From Email*"
id="form.fromEmail"
onChange={handleInputChange}
/>
</Col>
</Row>
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
);
}
export default ContactForm
You're logging the initialValues:
console.log(initialValues);
So you're always seeing the value of initialValues, which never changes. Nowhere are you observing state.
You can respond to state updates and log the updated state with useEffect for example:
useEffect(() => console.log(changing), [changing]);
This would log the value of changing any time that value changes.
You'd also observe updates to state in the UI if/when your UI uses state to render output. (Currently it does not.)
There are some things I suggest you to change:
<Form.Control
type="text"
required
name="fromName"
placeholder="From Name*"
aria-invalid="form.fromName"
onChange={handleInputChange}
/>
I'm not sure if those components belong to a framework like MaterialUI but would be better to have an attribute called value where you pass the state to handle a controlled component instead of an uncontrolled component:
<Form.Control
type="text"
required
name="fromName"
placeholder="From Name*"
aria-invalid="form.fromName"
onChange={handleInputChange}
value={changing.fromName} // Add this attribute
/>
Also, would be better if your initialState is outside of the function.
console.log(initialValues);
You should print the state instead of the initialValues, what you are updating is the state, not the initialValues.
setChanging({...changing, [e.target.name]: e.target.value});
this is because you didn't specify value attribute on your inputs.
in addition to this to see the changes on user type you must console.log the state (which is change here) not the initialValues.
example:
<Form.Control
type="text"
required
name="recipientName"
placeholder="Recipient Name*"
id="form.recipientName"
value={changing.fromName}
onChange={handleInputChange}
/>

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.

Reactjs antd defaultValue return undefined

im trying to make an edit function, the problem come when im trying to get the value from the form, say a user is editing his name, but he does not edit his address, this will make address is undefined even though i already set a defaultValue inside it, this works before in my non antd form, here is my code
form :
<Form onFinish={this.edit}>
<Typography>Email</Typography>
<Form.Item
name="email"
>
<Input defaultValue={user.Email} value={user.Email} className="email form-control col-sm-6"/>
</Form.Item>
<Typography>Full Name</Typography>
<Form.Item
name="name"
>
<Input defaultValue={user.FullName} value={user.FullName} className="email form-control col-sm-6"/>
</Form.Item>
<Typography>Admin</Typography>
<Form.Item
name="admin"
>
{
(user.IsAdministrator)
? <div>
<Select value="yes">Admin
<Select.Option value="no">Not Admin</Select.Option>
</Select>
</div>
: <div>
<Select value="no">Not admin
<Select.Option value="yes">Admin</Select.Option>
</Select>
</div>
}
</Form.Item>
<Typography>Active Status</Typography>
<Form.Item
name="aktif"
>
{
(user.IsActive)
? <Toggle className="switch-lg" checked/>
: <Toggle className="switch-lg"/>
}
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" className="login col-md-10">Submit</Button>
and here is how i get the value :
edit(values){
const name = values.name
const aktif = values.aktif
const index = this.state.id
console.log(values)
}
thanks before, anyhelp will be appreciated
As mentioned in the docs,
You cannot set value for each form control via value or defaultValue prop, you should set default value with initialValues of Form.
Example below:
<Form
onFinish={onFinish}
initialValues={{
residence: ['zhejiang', 'hangzhou', 'xihu'],
prefix: '86',
}}
>

Dynamic Form with initial values

Sorry for my english.
Like in this example
https://codesandbox.io/s/wonderful-lichterman-br63z?file=/index.js
Form.List is rendering the Array of "Fields" which initally is empty.
I would like to put my own array to be rendered from the start.
Expected result
you can do it using initialValues prop of Form.
Working example: https://codesandbox.io/s/bold-turing-g8ft6?file=/index.js
Docs: https://ant.design/components/form/#API
The docs are a bit short on explanation for the Form.List, and since a code sample is worth a thousand words...
This renders the dynamic form list with one item already visible:
const initialValues = {
users: [
{ age: undefined } // undefined will render the placeholder
]
};
<Form initialValues={initialValues}>
<Form.List name="users">
{(fields, { add }) => {
return (
<div>
{fields.map(field => (
<Row key={field.key}>
<Col>
<Form.Item
placeholder="age"
name={[field.age, 'age']}
>
<Input />
</Form.Item>
</Col>
<Col>
<Form.Item
placeholder="sex"
name={[field.sex, 'sex']}
>
<Input />
</Form.Item>
</Col>
<Col>
<Form.Item
placeholder="name"
name={[field.name, 'name']}
>
<Input />
</Form.Item>
</Col>
</Row>
))}
<button onClick={() => add()}>Add</button>
</div>
)
}}
</Form.List>
</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>
)
};

Resources