Cannot save data from Ant Design <Input.Group> - javascript

I tried making two input fields one for dimensions and one for weight, and both had seperate select drop down to allow the user to select a unit. I saw on Ant design docs that they had something similar, so I tried using that.
This is how I wanted it to be like:
Now i have filled my form with many other fields and they work just fine, on clicking the save button, I am not getting any data entered in the fields for dimensions or weight, nor their units. I have a standard save function which is called on 'onFinish' event:
const handleSubmit = (data) => {
console.log('data', data);
submit(data);
};
This is my code to generate the fields.
<Form onFinish={handleSubmit} >
<Row style={{ justifyContent: 'left' }}>
{<Col span={8}>
<div className="p-2 lbh-input">
<Form.Item
name="dimensions"
key="dimensions"
label="Dimensions (l x b x h)">
<Input.Group>
<Input
key='length'
name='length'
style={{ width: '15%' }}
type="number"
/>
<Input
key='breadth'
name='breadth'
style={{ width: '24%' }}
addonBefore="x"
type="number"
/>
<Input
key='height'
name='height'
style={{ width: '25%' }}
addonBefore="x"
type="number"
/>
<Select name='dimension_unit' key='dimension_unit' defaultValue="cm">
<Option value="mm">mm</Option>
<Option value="cm">cm</Option>
<Option value="inch">inch</Option>
<Option value="feet">feet</Option>
<Option value="m">m</Option>
</Select>
</Input.Group>
</Form.Item>
</div>
</Col>
}
{
<div className="p-2">
<Form.Item
key="weight"
name="weight"
label="Weight">
<Input.Group>
<Input
style={{ width: '50%' }}
type="number"
key="weight"
name="weight"
label="Weight"
className='noborderradius'
/>
<Select defaultValue="kg" name="weight_unit" key="weight_unit">
<Option value="kg">kg</Option>
<Option value="tonne">tonne</Option>
<Option value="g">g</Option>
</Select>
</Input.Group>
</Form.Item>
</div>}
</Row>
<button>SUBMIT</button>
</Form>
As you can see, i have tried using everythihg I can like label,name,key but no matter what happens, I get no data being sent no matter what I type in these two fields. What am i missing? Am i doing something wrong with <Form.item> ?
My ant design version is
"antd": "^4.3.4",

Input.Group is just for layout purposes, it does not group all your inputs into a single Form.Item. You still need to wrap all your inputs with Form.Item and attach the names there. Use the noStyle property to not override the Input.Group styling.
Also, defaultValue will give you this warning:
Warning: [antd: Form.Item] defaultValue will not work on controlled Field. You should use initialValues of Form instead.
So you can just do as it says, I've removed the styling for brevity
<Form
onFinish={handleSubmit}
initialValues={{ dimension_unit: 'cm', weight_unit: 'kg' }}
>
<Form.Item label="Dimensions (l x b x h)">
<Input.Group>
<Form.Item name="length" noStyle>
<Input type="number" />
</Form.Item>
<Form.Item name="breadth" noStyle>
<Input type="number" addonBefore="x" />
</Form.Item>
<Form.Item name="height" noStyle>
<Input type="number" addonBefore="x" />
</Form.Item>
<Form.Item name="dimension_unit" noStyle>
<Select>
<Option value="mm">mm</Option>
<Option value="cm">cm</Option>
<Option value="inch">inch</Option>
<Option value="feet">feet</Option>
<Option value="m">m</Option>
</Select>
</Form.Item>
</Input.Group>
</Form.Item>
<Form.Item label="Weight">
<Input.Group>
<Form.Item name="weight" noStyle>
<Input type="number" />
</Form.Item>
<Form.Item name="weight_unit" noStyle>
<Select>
<Option value="kg">kg</Option>
<Option value="tonne">tonne</Option>
<Option value="g">g</Option>
</Select>
</Form.Item>
</Input.Group>
</Form.Item>
<button>SUBMIT</button>
</Form>
Note that you don't need the key property.
demo: https://stackblitz.com/edit/react-41wakw?file=demo.tsx

What you can do is instead of wrapping the entire <Input.Group> with a single <Form.Item> you need to wrap each <Input> with its own <Form.Item> and give each one a unique key and name.
Working Code Sandbox
<Input.Group>
<Form.Item
name="length"
key="length"
>
<Input
style={{ width: '15%' }}
type="number"
/>
</Form.Item>
<Form.Item
key='breadth'
name='breadth'
>
<Input
style={{ width: '24%' }}
addonBefore="x"
type="number"
/>
</Form.Item>
...
</Input.Group>

Related

Validate select list with react-hook-form

I want to implement validation for React form using react-hook-form. For input value I implemented this:
<div className='input-group mb-3'>
<Controller
control={control}
name={"email"} // the key of json
defaultValue={""}
render={({ field }) => (
<input
{...field}
type="email"
className="form-control"
placeholder="Email"
aria-label="email"
onChange={(e) => field.onChange(e.target.value)}
/>
)}
/>
</div>
For me it's not clear how I need to implement it for select menu:
<div className='input-group mb-3'>
<select
className='form-control form-select'
name='budget'
id='budget'
required=''
data-msg='Please select your budget.'
>
<option value=''>Budget</option>
<option value='budget3'>More than $500,000</option>
</select>
</div>
Wat is the proper way to implement it?
somethings like this works?
<Controller
control={control}
name="budget"
rules={{
budget: {
required: "Required",
},
}}
render={({ field }) => (
<select name="budget" onChange={field.onChange} value={field.value}>
<option value="">Please select your budget</option>
<option value="budget3">More than $500,000</option>
<option value="budget2">$250,000 - $500,000</option>
<option value="budget1">$100,000 - $250,000</option>
{/* more budgets */}
</select>
)}
/>;
control is destructured from useForm like so:
const { controls, register, setValue, ...moreEls } = useForm();

method is not getting called on onChange event in formik react

I have to call below method using formik
const handleChange = async (e:any, values: any) => {
alert(e.target.value);
alert(values);
alert('Method called');
};
below is formik code.
<Formik initialValues={formInitialSchema}
validationSchema={formValidationSchema}
onSubmit={handleSubmit}>
<Form>
<div className="col-md-4">
<label htmlFor="protoColNo">Protocol No</label>
<Field
id="protoColNo"
className="form-control"
name="protoColNo"
placeholder="Enter the Protocol No"
/>
<p className="text-danger">
<ErrorMessage name="protoColNo" />
</p>
</div>
<div className="col-md-4">
<label htmlFor="activerequests">Active Requests</label>
<select
name="activeRequest"
style={{ display: 'block' }}
onChange= {(e)=>handleChange}>
<option value="No" >No </option>
<option value="Yes" >Yes</option>
<option value="All" selected>All </option>
</select>
<p className="text-danger">
<ErrorMessage name="activerequests" />
</p>
</div>
</div>
</Form>
</Formik>
I have one input filed and one drop down. As soon as user change the value of drop down I need to call handleChange method with the value of input filed and list. but method is not getting called. I dont know what wrong I am doing?
can you please help me with the same?
onChange= {(e)=>handleChange(e)}> //you forgot to call the handleChange
OR
onChange={handleChange}
You need to call the anonymous function inside the onChange event.
Use the following code :
onChange= {(e)=>handleChange(e)}

How can I customised the form of Ant Design?

I am trying to make inline form design using ant design but I am not able to make it customised version.
I have attached the code, image of output from the code and what I want form should look like.
Here is the code:
const layout = {
labelCol: { span: 8 },
wrapperCol: { span: 16 },
};
const layoutInline ={
labelCol: {
sm: {
offset: 0,
span: 20,
},
},
wrapperCol: {
sm: {
offset: 30,
span: 30,
},
},
}
return (
<div style={{width: "70%", padding: "4%"}}>
<div>
<Form
{...layoutInline}
form={form}
layout="inline"
>
<Form.Item label="Full Name" tooltip="This is a required field">
<Input placeholder="Full Name" />
</Form.Item>
<Form.Item
label="Age"
tooltip={{
title: 'Tooltip with customize icon',
icon: <InfoCircleOutlined />,
}}
onChange={updateAge}
value={age}
>
<Input placeholder="input placeholder" />
</Form.Item>
<Form.Item name="gender" label="Gender" rules={[{ required: true }]}>
<Select
placeholder="Select an option"
onChange={updateGender}
allowClear
>
<Option value="male">male</Option>
<Option value="female">female</Option>
<Option value="other">other</Option>
</Select>
</Form.Item>
{/* <Form.Item label="Full Name" tooltip="This is a required field">
<p>{gender} {age} {ethnicity} {AST} {platelets} {ASTupper} {ALT} {HBVDNA} {report}</p>
</Form.Item> */}
<Form.Item name="Ethnicity" label="Ethnicity" rules={[{ required: true }]}>
<Select
placeholder="Select an option"
onChange={updateEthnicity}
allowClear
>
<Option value="South-East-Asian">South East Asian</Option>
<Option value="South-Asian">South-Asian</Option>
<Option value="African">African</Option>
<Option value="Other">Other</Option>
</Select>
</Form.Item>
</Form>
</div>
It is coming out on the page like this.
What I want is that should look like this.
Can anyone guide me, how to achieve it?
1 - The value of offset and span follow the rulesĀ of Antd Grid Layout system and it cannot be more than 24 (24 columns).
2 - AddinglabelCol and wrapperCol on the Form element will apply the same layout for Every fields. As you'r desired deisgn, each fields has a different layout, so you'll need to apply it on each
3 - layout="inline" on Form means that they will just be all inline
Finally, the layout system on Antd Form is good to have vertically aligned fields. If you want to have a full control of the field display, you have to wrap each field your self and use custom style or Antd Grid columns.
You may need something like this :
https://codesandbox.io/s/form-methods-antd4123-forked-xo3zp?file=/index.js:922-2483
<Form form={form}>
<Row>
{* sm is only a breakpoint, you may need to add some more for better responsive *}
<Col sm={14}>
<Form.Item label="Full Name" tooltip="This is a required field">
<Input placeholder="Full Name" />
</Form.Item>
</Col>
<Col sm={{ offset: 2, span: 8 }}>
<Form.Item label="Age">
<Input placeholder="input placeholder" />
</Form.Item>
</Col>
</Row>
<Row>
<Col sm={8}>
<Form.Item
name="gender"
label="Gender"
rules={[{ required: true }]}
>
<Select placeholder="Select an option" allowClear>
<Option value="male">male</Option>
<Option value="female">female</Option>
<Option value="other">other</Option>
</Select>
</Form.Item>
</Col>
<Col sm={{ offset: 2, span: 8 }}>
<Form.Item
name="Ethnicity"
label="Ethnicity"
rules={[{ required: true }]}
>
<Select placeholder="Select an option" allowClear>
<Option value="South-East-Asian">South East Asian</Option>
<Option value="South-Asian">South-Asian</Option>
<Option value="African">African</Option>
<Option value="Other">Other</Option>
</Select>
</Form.Item>
</Col>
</Row>
</Form>
In my opinion try to avoid in-line style, add className to every component (even from Ant.) then in the CSS play with position (looks like you want flex and margin/padding)

Elements are not rendered inside scrollable view

I am building an application using React and Electron-JS.
I am using form to display some information. To this form style is applied asstyle={{ overflow: 'scroll', height: '45vh' }}. When Form items overflows, scrollbar is added to it. But the problem is when I scroll down, the items were hidden till then will not be rendered fully. But when the screen is resized, they become visible again. This happens like once in 10 times.
I cannot reproduce it always.
I think React is not rendering the items which are not visible on the visible screen to gain performance.
Following is the code for the form component:
const style = { margin: '5px', height: '3.3vh', labelAlign: 'left' };
const inputStyle = { padding: '3px', height: '26px' };
export const ObjectPane = React.memo(({ objDetails }) => (
<Form
fields={Object.keys(objDetails).map(key => {
let value = null;
if (objDetails[key] === undefined) value = 'NA';
else if (objDetails[key] === null) value = 'No Value';
else value = objDetails[key];
return {
name: [`${key}`],
value
};
})}
style={{ overflow: 'scroll', height: '45vh' }}
onScroll={() => {}}
>
<Form.Item label="Object" name="obj" style={style}>
<Input style={inputStyle} disabled />
</Form.Item>
<Form.Item label="Object Id" name="objId" style={style}>
<Input style={inputStyle} disabled />
</Form.Item>
<Form.Item label="Distance Long. [m] " name="longitude" style={style}>
<Input style={inputStyle} disabled />
</Form.Item>
<Form.Item label="Distance Lat. [m] " name="lateral" style={style}>
<Input style={inputStyle} disabled />
</Form.Item>
<Form.Item label="Velocity Long. [m/s]" name="vel_long" style={style}>
<Input style={inputStyle} disabled />
</Form.Item>
<Form.Item label="Velocity Lat. [m/s]" name="vel_lat" style={style}>
<Input style={inputStyle} disabled />
</Form.Item>
<Form.Item label="2 Wheeler Confidence" name="conf_twowheel" style={style}>
<Input style={inputStyle} disabled />
</Form.Item>
<Form.Item label="4 Wheeler Confidence" name="conf_fourwheel" style={style}>
<Input style={inputStyle} disabled />
</Form.Item>
<Form.Item
label="Pedestrian Confidence"
name="conf_pedestrian"
style={style}
>
<Input style={inputStyle} disabled />
</Form.Item>
<Form.Item
label="Stationary Confidence"
name="conf_stationary"
style={style}
>
<Input style={inputStyle} disabled />
</Form.Item>
<Form.Item label="Object Type" name="obj_type" style={style}>
<Input style={inputStyle} disabled />
</Form.Item>
<Form.Item label="Type Confidence" name="conf_obj" style={style}>
<Input style={inputStyle} disabled />
</Form.Item>
<Form.Item label="long_cu_aeb" name="long_cu_aeb" style={style}>
<Input style={inputStyle} disabled />
</Form.Item>
<Form.Item label="cross_vru_aeb" name="cross_vru_aeb" style={style}>
<Input style={inputStyle} disabled />
</Form.Item>
<Form.Item label="long_cu_fcw" name="long_cu_fcw" style={style}>
<Input style={inputStyle} disabled />
</Form.Item>
<Form.Item label="cross_vru_fcw" name="cross_vru_fcw" style={style}>
<Input style={inputStyle} disabled />
</Form.Item>
<Form.Item label="cyc_ped_tipl" name="cyc_ped_tipl" style={style}>
<Input style={inputStyle} disabled />
</Form.Item>
</Form>
));
How can I make this work as expected? Please let me know if any more information needs to be added here.

React - How to get input from looped <form>?

I am new on React.
I have a condition which is to loop the form, please help me
Here is the code:
this.state.products.map(product => {
<form onSubmit={this.handleSubmit}>
<select name="size" className="form-control" style={{height: '46px;'}}>
<option key="1" value="1">Red</option>
<option key="2" value="2">Yellow</option>
<option key="3" value="3">Green</option>
</select>
<input type="submit" value="Pick This" className="form-control" onClick={() => this.handleSubmit} />
</form>
});
If there was 3 form, how to get the selected value from clicked submit button form?
Or is there another simple way?
Thank you
One method would be changing how your onSubmit function is handled.
So you could pass which index of products you are submitting like so
this.state.products.map((product, i) => {
<form onSubmit={event => this.handleSubmit(event, i)}>
<select name="size" className="form-control" style={{height: '46px;'}}>
<option key="1" value="1">Red</option>
<option key="2" value="2">Yellow</option>
<option key="3" value="3">Green</option>
</select>
<input type="submit" value="Pick This" className="form-control" onClick={() => this.handleSubmit} />
</form>
});
It also looks like your form is uncontrolled, which another possibly is having the select change a value in state.
<select name="size" onChange={e => this.handleChange(e, i)} className="form-control" style={{height: '46px;'}}>
<option key="1" value="1">Red</option>
<option key="2" value="2">Yellow</option>
<option key="3" value="3">Green</option>
</select>
and in your handleChange, you would change a value in state that would correspond to the product from your state.
You can use a ref to get form values from the DOM.
Here you need one ref per product, so you could use the index of product to save the ref and also to submit de form.
class Example extends Component {
constructor(props) {
super(props);
this.state = {
products: [],
};
this.selectByProduct = {};
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event, productIndex) {
event.preventDefault();
const size = this.selectByProduct[productIndex].value;
console.log(`you submitted the size ${size} of product ${productIndex}`)
}
render() {
return this.state.products.map((product, i) => (
<form onSubmit={event => this.handleSubmit(event, i)}>
<select ref={select => this.selectByProduct[i] = select} name="size" className="form-control" style={{height: '46px;'}}>
<option key="1" value="1">Red</option>
<option key="2" value="2">Yellow</option>
<option key="3" value="3">Green</option>
</select>
<input type="submit" value="Pick This" className="form-control" />
</form>
));
}
}

Categories

Resources