Display input fields based on a variable number in state - javascript

I have the below piece of code. I have defined a const in state called items. This is the dropdown selection. It has value 0, 1 and 2 and these indicate no. of dependents.
Once user selects this dropdown, i then update the value of selected dropdown in dependents constant using useState.
I want to display input field below this which will allow user to enter dependents age. For e.g. user selects 2 in dropdown. I want to show 2 input fields below which will allow user to enter the age of 2 dependents. Similarly, if i select 1- i should only show 1 input field. In that way it should show dynamically the number of input fields as user selects in dropdown.
Can someone please let me know how to achieve it.
function App() {
const [items] = useState([
{ label: "0", value: "0" },
{ label: "1", value: "1" },
{ label: "2", value: "2" }
]);
const [dependents, setDependents] = useState("0");
return (
<div className="App">
Select Dependents:
<select onChange={e => setDependents(e.currentTarget.value)}>
{items.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))
}
</select>
</div>
);
}
"

Create an array based on the selected value and map it to render the input:
<div className="App">
Select Dependents:
<select onChange={e => setDependents(e.currentTarget.value)}>
{items.map(({ label, value }) => (
<option key={value} value={value}>
{label}
</option>
))
}
</select>
{[...Array(+dependents)].map((_,index)=>{
return <input type="text" key={index} />
})
}
</div>
Note :
[...Array(number)] creates an array of undefined items with length equals to number, and +number converts a string to number like +"4" gives 4

Related

how can i get dynamic value input and store it into the state

I am using react js. I am trying to get the dynamic input values from a modal, the problem is I am not able to get the input values in a proper way. I am trying to get when the user selects the size the state will save only one value small or extra-large also user can select multiple values in extra ingredirents which will store in the state.
The above image is my UI, as you can see I can select multiple values in the radio button which I don't want. I know where the problem is but didn't get any solution. I have commented on my jsx code where the problem is.
Here is the radio button and checkbox jsx code. the input values are dynamic I have hardcoded the values
// Radio buttons
{products.options.map((product, i) => {
return (
<li onChange={(e) => getItemValues(e.target, product)}>
<label className="container_radio">
Medium size
<span>+ $5.00</span>
<input
type="radio"
value={5.00}
name={options.title} // Here i have added dynamic value that is why the radio button is selecting multiple
/>
<span className="checkmark"></span>
</label>
</li>
<li onChange={(e) => getItemValues(e.target, product)}>
<label className="container_radio">
Extra Largse size
<span>+ $8.00</span>
<input
type="radio"
value={8.00}
name={'Extra Largse size'} // If I wrote like this the radio button are selecting only one
/>
<span className="checkmark"></span>
</label>
</li>
);
})}
// checkboxes, checkboxes will be more I just hardcoded only one
{product.ingredients.map((ingredient) => {
return (
<li onChange={(e) => getItemValues(e.target, product)}>
<label className="container_check">
Extra Tomato
<span>+ $2</span>
<input
type="checkbox"
value={2}
name={'Extra-Tomato'}
/>
<span className="checkmark"></span>
</label>
</li>
);
})}
Here is the function where I am trying to store the data
const [itemDetail, setItemDetail] = useState([]);
const getItemValues = (e, product) => {
setItemDetail((prevValue) => {
const existingProduct = prevValue.find(
(item) => item.title === product.title
);
if (existingProduct) {
existingProduct.options = {
...existingProduct.options,
[e.name]: e.value,
};
return prevValue;
} else {
/* new entry */
return [
...prevValue,
{ title: product.title, options: { [e.name]: e.value } },
];
}
});
};
If I select extra large and ketchup the output looks like the below code: as you can see I am getting only one value which is ketchup, I should get also the extra large value maybe there is a problem with my function.
[{options: {ketchup: '1'}
title: "ketchup}]
My expected output is:
[{title: 'Barnes Chapman', options:{extra large: '8.0', ketchup: '1.00' } }]
Also, i want if unselect the ketchup the ketchup value will be removed from the state also for the radio buttons.

Update Select Option list based on other Select field selection ant design

<Form
layout="vertical"
size="medium"
className="test-form"
requiredMark={false}
onFinish={onFinish}
>
<Form.Item
name="companyId"
label="Company/Customer"
rules={[{ required: true, message: "Please select Company!"}]}
>
<Select
onChange={this.handleSelectCompanyOnchange}
style={{ width: "50%" }}
name="companyId"
>
{users.map((user, index) => {
return (
<Option key={index} value={user.companyID}>
{user.companyName}
</Option>
);
})}
</Select>
</Form.Item>
<Form.Item
label="Products"
name="products"
rules={[{ required: true, message: "Please select Products!"}]}
>
<Select mode="multiple" allowClear style={{ width: "70%" }}>
{products.map((product, index) => {
if (this.state.companyId == product.companyId) {
return (
<Option key={index} value={product.id}>
{product.productName}
</Option>
);
}
})}
</Select>
</Form.Item>
</Form>
I am trying to achieve Options in Products Select element changes according to the Company Select onChange selection.
I have specified onChange in Select and calling this.handleSelectCompanyOnchange. In which I get selected companyId.
In this.state.companyId I had set companyId manually which I will remove.
I am really new to ant design and not able to figure out how to update the Products list once Company is selected.
Here, users and products are json as below.
users:
[{
companyID: 2
companyName: "TEST1"
},{
companyID: 7
companyName: "TEST2"
}]
products:
[{
companyId: 2
id: 1
productName: "TESTProduct1"
},{
companyId: 7
productName: "TESTProduct2"
id: 2
},{
companyId: 7
id: 3
productName: "TESTProduct3"
},{
companyId: 7
id: 4
productName: "TESTProduct4"
}]
However, I have tried getValueFromEvent but not able to achieve this. I am using Ant design Form and Select for this. Also I did referred to https://github.com/ant-design/ant-design/issues/4862 and how to get field value on change for FormItem in antd
Here is what you need to achieve it.
Use onValuesChange prop of the Form. This is the best place to perform setState when it comes to antd Form field changes, not on Select or Input onChange.
<Form onValuesChange={handleFormValuesChange}>
...
</Form>
A form instance (hook). This is optional in your case, but this is useful on setting and getting form values. See more here about it.
const [form] = Form.useForm();
<Form form={form} onValuesChange={handleFormValuesChange}>
...
</Form>
This is the product options render looks like, a combination of map and filter where selectedCompanyId comes from state. Take note that don't use index as key if the fixed length of the list is unknown, the react will confuse on this and you will get some logical error. Use some unique id.
<Form.Item label="Products" name="product">
<Select>
{products
.filter((product) => product.companyId === selectedCompanyId)
.map((product) => (
<Option key={product.id} value={product.id}>
{product.productName}
</Option>
))}
</Select>
</Form.Item>
And here is the handleFormValuesChange
const handleFormValuesChange = (changedValues) => {
const formFieldName = Object.keys(changedValues)[0];
if (formFieldName === "company") {
setSelectedCompanyId(changedValues[formFieldName]); // perform setState here
form.setFieldsValue({product: undefined}) //reset product selection
}
};
Here is the complete working code in react hooks:
the idea here is that you only need to watch the value change in the state.
For example, your select should "watch" a value of state and then you can easily update the state via its own setState method of React. Inside of an onChange event, you can simply just do something with our state.
<Select
value={state.productId}
onChange={e => {// Do something}}
>
{...}
<Select/>
Below is my example code how did I update the day every time I reselect week selection. Hopefully that this can help you.
import { Divider, Select } from 'antd';
import React, { useState } from 'react';
export function Example(): JSX.Element {
const [state, setState] = useState<{week: number, day: number}>({
day: 1,
week: 1
});
const weeks = [1,2,3,4];
const days = [1,2,3,4,5];
return <>
<Select
value={state.week}
onChange={(value) => setState({ week: value, day: 1})}
>
{
weeks.map(week => {
return <Select.Option
key={week}
value={week}
>
{week}
</Select.Option>;
})
}
</Select>
<Divider/>
<Select
value={state.day}
onChange={(value) => setState({...state, day: value})}
>
{
days.map(day => {
return <Select.Option
key={day}
value={day}
>
{day}
</Select.Option>;
})
}
</Select>
</>;
}
Lets say you want to update your option list based on data you get from backend;
note:categories is an array object. From this array you take out label and value for each option, see below:
const newOptions = categories.map((item, index) => {
return {
label: item.name,
value: item._id,
};
});
Then use newOptions inside your form like that:
<Form.Item label="anyName" name="anyName">
<Select style={{ width: 220 }} onChange={ handleChange } options={ newOptions } />
</Form.Item>

react-select 2 setting value/label

I am using react-select 2 and trying to set value on form that needs to perform update of some data fetched from server.
I have tried solution:
handleSelectChange(selectedOption){
this.setState({ selectedOption });
}
const options = [
{ value: 'Value 1', label: 'Value 1' },
{ value: 'Value 2', label: 'Value 2' },
]
<Select
options={options}
onChange={(selectedOption)=>this.handleSelectChange(selectedOption)}
autoFocus={true}
value={options.find(option => option.value === data.valueTyppe)}
/>
By using this it is not possible to change (visualy) label in select input - value changes on select but label stays as one defined by data.ValueType.
I think your problem comes from not allowing full control of the Select input.The value of the Select input should be the component state value property, same as the onChange calback is.
return(
<Select
options={options}
onChange={this.handleSelectChange}
autoFocus={true}
value={this.state.selectedOption}
/>
try this working examle
I have used this solution and it works for me.
First Value/Label pair is set as on defined in options that have value === data.FacilityType (saved string in database).
Then it enables change of option where value/label pair is also updated in Select.
<Select
options={options}
onChange={(selectedOption)=>this.handleSelectChange(selectedOption)}
autoFocus={true}
defaultValue={options.find(option => option.value === data.facilityType)}
/>

Ant Design reset select

I have 2 <Select>'s. The values in the second are dependant on the selection made on the first. When I change the selected item in the first, the available options on the second update. But if I already have a selection made on the second, that option remains selected even if it isn't supposed to be available based on a change to the first select.
How can I reset the second select to have nothing selected when a change is made to the first select?
First Select:
<FormItem {...formTailLayout}>
<FormTitle>Operation</FormTitle>
{getFieldDecorator('Operation', {
rules: [
{
required: true
}
]
})(
<Select
showSearch
placeholder="Select an option"
onChange={this.handleOperationChange}
>
{operations.map(operation => (
<Option value={operation.operation_id}>
{operation.operation_name}
</Option>
))}
</Select>
)}
</FormItem>
Second Select:
<FormItem {...formTailLayout}>
<FormTitle>Metric</FormTitle>
{getFieldDecorator('Metric', {
rules: [
{
required: true
}
]
})(
<Select
showSearch
placeholder="Select an operation first"
onChange={this.handleMetricChange}
>
{matrics
.filter(
metric => metric.operation_fk === operation_fk
)
.map(metric => (
<Option value={metric.metric_name}>
{metric.metric_name}
</Option>
))}
</Select>
)}
</FormItem>
You need to take a look at Coordinated Controls example mentioned on ant-design page. You can simply use setFieldsValue in your first onChange method to set the value of second select field.
handleOperationChange = () => {
this.props.form.setFieldsValue({
Metric: undefined
})
}
I have created a sandbox demo.
In antd, In Class Component, Using Ref, Clear or reset select list value or form item value
add formRef = React.createRef(); just below class component, like:
export default class TestClass extends Component { formRef = React.createRef(); }
add ref={this.formRef} in <Form /> component like this <Form ref={this.formRef}/>
add this line on btn click or in any function you want
this.formRef.current.setFieldsValue({ network: undefined });
Here network in above step is the name of form item
<Form.Item name="network" label="Network"></Form.Item>
Inside handleOperationChange method use resetfileds, this gonna reset your second select box.
this.props.form.resetFields('Metric');
<Select
className="mt-3"
style={{ width: "100%" }}
placeholder="Select your Sub Category"
onChange={handleChangeSubCategory}
disabled={categoryGroup.category === null}
value={categoryGroup.subcategory || undefined}
>
{subCategory.map(item => (
<Option key={item} value={item} label={item}>
<div>
<Avatar style={{ background: "#10899e" }}>
{item[0]}
</Avatar>{" "}
{item}
</div>
</Option>
))}
</Select>
If functional component is used, then we can use Form:
const [form] = Form.useForm()
and it is possible to clear value like this:
const someMethodToClearCurrentSelection = () => {
// ... the code is omitted for the brevity
form.setFieldsValue({ fooProduct: undefined })
}
and our control looks like this:
<Form form={form} name="basic" onFinish={onFinish} layout="vertical">
<Form.Item
key="fooProduct"
name="fooProduct"
label="Some product"
className={s.fooContainer}
rules={[
{
required: true,
message: `Field 'Some produc' is required`,
},
]}
>
<Select
showSearch
optionFilterProp="children"
filterOption={(input, option) =>
option?.children.toLowerCase().includes(input.toLowerCase())
}
allowClear
onChange={handleMarkClick}
>
{products.map((option) => (
<Option key={option.id} value={option.id}>
{option.name}
</Option>
))}
</Select>
</Form.Item>
Read more in antd docs here and examples while migrating from v3 to v4
You can make use of the useEffect() hook.
Define a useForm() custom hook fir your form.
Example: const [form] = Form.useForm();`
Wrap your 1st and 2nd select boxes inside the form and use <Form.Item> to define the input on the form. And whenever the first select's input is changed, clear the 2nd select values in useEffect() hook.
Example:
useEffect(() => {
form.setFieldsValue({
marketplace: [] //2nd select name
});
}, [selectedRegion]); //first select's value
This work perfect for me.

React Semantic UI - add key to options in Dropdown menu

I have this Dropdown menu instance:
<Dropdown
selection
options={this.state.options}
search
value={value}
onChange={this.handleChange}
onSearchChange={this.handleSearchChange}
/>
and when my backend returns response, which is then set as state and it is structured like this:
"options": [
{
"text": "New York,All Airports (NYC) , USA",
"value": "NYC"
},
{
"text": "New York,Newark Liberty Intl (EWR), USA",
"value": "EWR"
},
{
"text": "New York,John F Kennedy (JFK), USA",
"value": "JFK"
},
{
"text": "New York,La Guardia (LGA), USA",
"value": "LGA"
}
]
...I get this warning:
Warning: flattenChildren(...): Encountered two children with the same
key, 1:$BLZ. Child keys must be unique; when two children share a
key, only the first child will be used.
in select (created by Dropdown)
in div (created by Dropdown)
in Dropdown (created by SearchForm)
How do I add keys to these elements to prevent this warning?
So looking at the code for the Semantic UI source for the dropdown component, the render options function converts your passed in options into a array of DropdownItem components:
renderOptions = () => {
const { multiple, search, noResultsMessage } = this.props
const { selectedIndex, value } = this.state
const options = this.getMenuOptions()
if (noResultsMessage !== null && search && _.isEmpty(options)) {
return <div className='message'>{noResultsMessage}</div>
}
const isActive = multiple
? optValue => _.includes(value, optValue)
: optValue => optValue === value
return _.map(options, (opt, i) => (
<DropdownItem
key={`${opt.value}-${i}`}
active={isActive(opt.value)}
onClick={this.handleItemClick}
selected={selectedIndex === i}
{...opt}
// Needed for handling click events on disabled items
style={{ ...opt.style, pointerEvents: 'all' }}
/>
))
}
the key for this array is set by taking the value prop and appending the index to it:
key={`${opt.value}-${i}`}
which should always be unique since the index is used but there is another part of the code for hidden inputs
renderHiddenInput = () => {
debug('renderHiddenInput()')
const { value } = this.state
const { multiple, name, options, selection } = this.props
debug(`name: ${name}`)
debug(`selection: ${selection}`)
debug(`value: ${value}`)
if (!selection) return null
// a dropdown without an active item will have an empty string value
return (
<select type='hidden' aria-hidden='true' name={name} value={value} multiple={multiple}>
<option value='' />
{_.map(options, option => (
<option key={option.value} value={option.value}>{option.text}</option>
))}
</select>
)
}
in this one the key is set to only the value, not the value plus index.
<option key={option.value} value={option.value}>{option.text}</option>
this might be your problem, if you have duplicate values then the key will not be unique. Double check the options list to make sure you don't have duplicate values.

Categories

Resources