set initalValues in nested dynamic form | Antd - reactjs

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

Related

Setting the value of an input field in antd react JS

I want to set the value of a field based on what I have in the database. Make it ineditable but also want the ability for customers to copy that value. I am able to read the values on submit but I dont know how to set them initially. I am using this
form.setFieldsValue({
clientID: 'value from database',
});
but its not working.
const APIAccess = () => {
const [form] = Form.useForm();
const dbvalues = "some value from database"
form.setFieldsValue({
clientID: dbvalues,
});
const handleSubmit = (value) =>
{
const payload = {
"appName" : form.getFieldValue('appName') ,
}
return (
<Form
name="control-hooks"
form={form}
>
<Form.Item
label="App Name"
name="appName"
rules={[
{
required: true,
message: 'Please select an App Name!',
},
]}
>
<Input />
</Form.Item>
<Form.Item
label="Your Client ID"
name="clientID"
>
<Input.Group >
<Space>
<Input/>
<Tooltip title="copy your Client ID">
<Button icon={<CopyOutlined />} onClick={() => {navigator.clipboard.writeText(clientID)}}/> </Tooltip>
</Space>
</Input.Group>
</Form.Item>
<Form.Item
>
<Button type="primary" htmlType="submit" onClick={handleSubmit}>
Save
</Button>
</Form.Item>
</Form>)
You don't want to programmatically set each initial value. Instead, pass all the initial values to the Form component:
<Form
initialValues={{
clientID: some_client_id,
}}
/>

How do you get a nested value item in ant design

im quite new on reactJS and also ant design. right now im trying to get a value from a Form.List that i want to make it / render it as json nested data output.
my full code :
import { MinusCircleOutlined, PlusOutlined } from '#ant-design/icons';
import { Button, Form, Input, Space, DatePicker, Select } from 'antd';
import axios from 'axios'
import { useNavigate } from 'react-router-dom'
import Cookies from "js-cookies";
import moment from 'moment';
import 'moment/locale/zh-cn';
const Stockpickingnew = ({ title }) => {
const options = [
{
value: '1',
label: 'True',
},
{
value: '0',
label: 'False',
},
{
value: '7',
label: 'product_tmpl_id'
},
];
const Navigate = useNavigate()
const dateFormat = ['DD-MM-YYYY'];
//---------------------------------------------------------------------------------------------------------------
let headers = {
"Authorization": "Bearer " + Cookies.getItem('access_token')
}
const onFinish = (values) => {
console.log('Success:', values);
let stockpick = {
date: moment(values.date).format("DD-MM-YYYY"),
origin: values.origin,
picking_type_id: values.picking_type_id,
location_id: values.location_id,
location_dest_id: values.location_dest_id,
stock_move_ids: [{
demand: values.demand,
done: values.done,
product_uom: values.product_uom,
product_tmpl_id: values.product_tmpl_id,
}]
};
console.log(JSON.stringify(stockpick))
let params = JSON.stringify(stockpick)
axios.post('http://127.0.0.1:5000/api/stockpickings', params, { headers })
.then(() => {
Navigate('/')
})
.catch(error => {
if (error.response) {
console.log(error.response);
}
});
};
const onFinishFailed = (errorInfo) => {
console.log('Failed:', errorInfo);
};
//---------------------------------------------------------------------------------------------------------------
return (
<>
<div className='new'>
<div className="top">
<h1>{title}</h1>
</div>
<div className="bottom">
<div className="stockPicking">
<Form
name="stockPickings"
layout="vertical"
onFinish={onFinish}
onFinishFailed={onFinishFailed}
autoComplete="off"
>
<div className="left">
<Form.Item
label="Origin :"
name='origin'
>
<Select
options={options}
placeholder="Origin"
/>
</Form.Item>
<Form.Item
label="Picking Type :"
name='picking_type_id'
>
<Select
options={options}
placeholder="Picking Type"
/>
</Form.Item>
<Form.Item
label="Date :"
name='date'
>
<DatePicker
format={dateFormat}
onChange={(dateInMomentFormat, dateInStringFormat) => {
console.log(dateInStringFormat);
}}
/>
</Form.Item>
</div>
<div className="right">
<Form.Item
label="Location :"
name='location_id'
>
<Select
options={options}
placeholder="Location"
/>
</Form.Item>
<Form.Item
label="Destination :"
name='location_dest_id'
>
<Select
options={options}
placeholder="Destination"
/>
</Form.Item>
</div>
<div className="stockMove">
<Form.Item>
<Form.List name="stock_move_ids">
{(fields, { add, remove }) => (
<>
{fields.map((field) => (
<Space
key={field.key}
style={{
display: 'flex',
marginBottom: 8,
}}
align="baseline"
>
<Form.Item
{...field}
name={[field.name, 'demand']}
key={[field.key, 'demand']}
rules={[
{
required: true,
message: 'Missing Demand',
},
]}
>
<Input placeholder="Demand" />
</Form.Item>
<Form.Item
{...field}
name={[field.name, 'done']}
key={[field.key, 'done']}
>
<Select
options={options}
placeholder="Done"
/>
</Form.Item>
<Form.Item
{...field}
name={[field.name, 'product_uom']}
key={[field.key, 'product_uom']}
rules={[
{
required: true,
message: 'Missing product_uom',
},
]}
>
<Select
options={options}
placeholder="product_uom"
/>
</Form.Item>
<Form.Item
{...field}
name={[field.name, 'product_tmpl_id']}
key={[field.key, 'product_tmpl_id']}
rules={[
{
required: true,
message: 'Missing product_tmpl_id',
},
]}
>
<Select
options={options}
placeholder="product_tmpl_id"
/>
</Form.Item>
<MinusCircleOutlined onClick={() => remove(field.name)} />
</Space>
))}
<Form.Item>
<Button type="dashed" onClick={() => add()} block icon={<PlusOutlined />}>
Add field
</Button>
</Form.Item>
</>
)}
</Form.List>
</Form.Item>
</div>
<Form.Item>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</Form>
</div>
</div>
</div>
</>
)
}
export default Stockpickingnew
im sorry if it's really hard to read but basically, what i really want to do is my Form.List can get a value as nested data like :
stock_move_ids: [{
demand: values.demand,
done: values.done,
product_uom: values.product_uom,
product_tmpl_id: values.product_tmpl_id,
}]
my console.log (values) and console.log JSON.stringify(stockpick) do have different result as image below.
first one is from console.log values and the bottom one is from console.log stockpick
Screenshoot here
stock_move_ids values have 0th index you can access it like this.
let stockpick = {
date: moment(values.date).format("DD-MM-YYYY"),
origin: values.origin,
picking_type_id: values.picking_type_id,
location_id: values.location_id,
location_dest_id: values.location_dest_id,
stock_move_ids: [
{
demand: values?.stock_move_ids?.[0]?.demand,
done: values?.stock_move_ids?.[0]?.done,
product_uom: values?.stock_move_ids?.[0]?.product_uom,
product_tmpl_id: values?.stock_move_ids?.[0]?.product_tmpl_id,
},
],
};

how to implement form for mapped child component

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

Why can't I get values of Date and Text Area in Formik?

I am using Formik and Yup for a form control in React application. I use also Semantic UI. In the application, when I click the submit button, whereas I can read the values from FormField elements and see them on Console, I can not get the value of Date and Text Area elements and they appear blank on Console. How can I solve this out?
Here I define the intial values.
const initialValues = {
jobTitle: { id: "" },
deadline: "",
description: "",
};
Then here I try to get the values from form element
return (
<div>
<Card fluid>
<Card.Content>
<Card.Header>Create A New Job Ad</Card.Header>
<Divider inverted />
<Formik
initialValues={initialValues}
validationSchema={jobAdCreateSchema}
onSubmit={(values) => {
handleSubmit(values);
}}
>
{({ values, setFieldValue }) => (
<div>
<pre>{JSON.stringify(values, undefined, 2)}</pre>
<Form className="ui form">
<FormField>
<label>Job Title</label>
<Dropdown
selection
placeholder="Select a Job Title"
name="jobTitle"
fluid
options={jobTitleOption}
value={values.jobTitle.id}
onChange={(_, { value }) =>
setFieldValue("jobTitle.id", value)
}
/>
</FormField>
<FormField>
<label>Application Deadline</label>
<input
name="deadline"
style={{ width: "100%" }}
type="date"
placeholder="Application Deadline"
value={values.deadline}
onChange={formik.handleChange}
/>
</FormField>
<FormField>
<label>Job Description</label>
<TextArea
name="description"
placeholder="Job Description"
style={{ minHeight: 100 }}
value={values.description}
onChange={formik.handleChange}
/>
</FormField>
<FormField>
<Button color="green" type="submit">
Submit
</Button>
</FormField>
</Form>
</div>
)}
</Formik>
</Card.Content>
</Card>
</div>
);
formik isn't defined, so your assigning an onChange function that doesn't exist.
Destructure handleChange from the argument, then assign it to the inputs like so:
{({ values, setFieldValue, handleChange }) => (
//...
<input
name="deadline"
style={{ width: "100%" }}
type="date"
placeholder="Application Deadline"
value={values.deadline}
onChange={handleChange}
/>
)}
Live demo

Ant design <Form.List> create static array of forms

I am using antd with react to develop an application.
<Form.List name="secondaryContacts">
{(fields, { add, remove }) => {
return (
<div>
{fields.map((field, index) => (
<Form.Item
{...formItemLayoutWithOutLabel}
label={index === 0 ? "" : ""}
required={false}
key={field.key}
>
<Form.Item
{...field}
validateTrigger={["onChange", "onBlur"]}
rules={[
{
required: true,
validator: phoneNumberValidator
}
]}
>
<Input
placeholder="Secondary Contact"
addonAfter={
fields.length >= 1 ? (
<MinusCircleOutlined
onClick={() => {
remove(field.name);
}}
/>
) : null
}
/>
</Form.Item>
</Form.Item>
))}
<Form.Item {...formItemLayoutWithOutLabel}>
<Button
type="dashed"
onClick={() => {
add();
}}
style={{ width: "100%" }}
>
<PlusOutlined /> Add Secondary Contact
</Button>
</Form.Item>
</div>
);
}}
</Form.List>;
Above is the code I am using to add dynamic form fields with validation using Form.List.
Now I have a specific scenario where I need to show 7 Sliders(https://ant.design/components/slider/) for the selected time slot and store them in an array, so I thought of using Form.List and keep all sliders inside just like above(except that it's static).
But I am not clear how I can achieve it with Form.List and there are very few examples on the internet.
I have a scenario where I need to have an array of forms and club them as an array using Form.List.
You can use the initialValue property to set the static data
Example:
const staticValue = [{ formItem1: 'value1', formItem2: 'value2'}];
<Form.List name="formListName" initialValue={staticValue}>
{(fields, { add, remove }, { errors }) => (
fields.map((field) => (
<>
<Form.Item {...field} name={[field.name, 'formItem1']}>
<Input placeholder="Field 1" />
</Form.Item>
...
You still need <Form> component
Try
<Form>
<Form.List>
</Form.List>
</Form>

Resources