I am having a problem where I am trying use value in map. Is it possible to use value from state when mapping? How should I do it correctly?
const inputName=[
{id:1, label: 'Login',type:'text',name:'login',placeholder:'Enter login'},
{id:2, label: 'Password',type:'text',name:'password',placeholder:'Enter password'},
{id:3, label: 'Password',type:'password',name:'password2',placeholder:'Enter password again'},
{id:4, label: 'Name',type:'text',name:'firstName',placeholder:'Enter name'},
{id:5, label: 'Surname',type:'text',name:'lastName',placeholder:'Enter surname'},
{id:6, label: 'Position',type:'select',name:'role',option1:'Worker',option2:'Manager'},
]
/*My state*/
state = {
login: "",
password: "",
password2: "",
firstName: "",
lastName: "",
enable: true,
role: {
name: ""
}
};
/* My map */
/* How use value from state in my input mapping? */
const inputs = inputName.map(input => (
<FormGroup key={input.id}>
<Label>{input.label}</Label>
<Input
type={input.type}
name={input.name}
// value={} idk how get every value from state here
onChange={this.handleChange}
placeholder={input.placeholder}
>
<option>{input.option1}</option>
<option>{input.option2}</option>
</Input>
</FormGroup>
));
If I understand the question correctly, you could use your name property to access the state value by using the "bracket notation":
const inputs = inputName.map(input => (
<FormGroup key={input.id}>
<Label>{input.label}</Label>
<Input
type={input.type}
name={input.name}
value={this.state[input.name]} // access the value from the state
onChange={this.handleChange}
placeholder={input.placeholder}
>
<option>{input.option1}</option>
<option>{input.option2}</option>
</Input>
</FormGroup>
));
This only works if the key of your state property is equal to the name
You just have to find the value corresponding to the label property:
const inputs = inputName.map(input => (
<FormGroup key={input.id}>
<Label>{input.label}</Label>
<Input
type={input.type}
name={input.name}
value={this.state[input.label.toLowerCase()]} //this.state['login']
onChange={this.handleChange}
placeholder={input.placeholder}
>
<option>{input.option1}</option>
<option>{input.option2}</option>
</Input>
</FormGroup>
));
Related
I'm receiving the data from api like cites nested into state objects
Example:
const data = [
{
id: 1,
name: 'State One',
cities: [
{
id: 1,
state: 'State One',
name: 'City One'
},
{
id: 2,
state: 'State One',
name: 'City Two'
},
{
id: 3,
state: 'State One',
name: 'City Three'
}
]
},
{
id: 2,
name: 'State 2',
cities: [
{
id: 4,
state: 'State 2',
name: 'City 5'
}
]
}
]
I have to give the Select options of the Cities according to Parent State. Lets say User selected State One in State Select Field then There should be only cities options of the State One in next City Field
How to Configure it ?
Currently; I have created hollow structure of the Select Input Fields but can't find anything how can I configure it. I need little help or any idea to start with.
This is current code;
<Col lg="6" md="12" className="mb-1">
<Label className="form-label py-1" for="state">
State
</Label>{' '}
<Row></Row>
<Select
id="state"
options={stateOptions}
defaultValue={stateOptions[0]}
onChange={(choice) => console.log(choice.value)}
/>
</Col>
<Col lg="6" md="12" className="mb-1">
<Label className="form-label py-1" for="city">
City
</Label>{' '}
<Row></Row>
<Select
id="city"
classNamePrefix="select"
options={cityOptions}
onChange={(choice) => console.log(choice.value)}
/>
</Col>
I have seen some articles but they suggest to use npm libraries but I can't use them because data is a lot different then that I want to handle.
You can keep track of the currently selected state and update the cities that the second Select takes.
Also added some comments to explain what the functions are doing.
export default function App() {
const [state, setState] = useState(null);
const [city, setCity] = useState(null);
const onStateChange = (option) => {
setState(option);
// to remove city if a different state is selected
if (!option || option?.value !== state?.value) setCity(null);
};
const onCityChange = (option) => {
setCity(option);
};
// a separate useState for cities is not needed
// as cities depend on the selected state, it can be determined when state changes
const cities = useMemo(() => {
if (!state) return [];
return getOptions(data.find((el) => el.id === state.value).cities);
}, [state]);
return (
<div>
<Select options={states} value={state} onChange={onStateChange} />
<hr />
<Select options={cities} value={city} onChange={onCityChange} />
</div>
);
}
I have a CustomInput from reactstrap that is not showing the correct state.name when clicked. I am passing a stringifiedJSON object as value on the option, then The handle change is parsing the string back into an object. I can console.log(state) and see the object just fine.
If I set the onChange to onChange={({target}) => setCountry(target.value)} this renders the selected option correctly, If I select united states, it shows united states, If I select Mexico it shows Mexico so on and so forth.
However, When I set my onChange to onChange={handleChange} with handleChange being this below, It will only show the first item in the array, In my case United States. I can select Mexico, the console.log will show the updated state, However the select option looks like United States is still chosen.
const handleChange = async(event) => {
setCountry(event.target.value)
const obj = JSON.parse(event.target.value)
setCountry(obj)
}
<Input
type="select"
id="country"
name="country"
className="mb-3"
value={country}
onChange={({target}) => setCountry(target.value)} <--- this renders correctly
>
{numberCountries.map((country, index) => (
<Fragment>
<option key={index} value={JSON.stringify(country)}>{country?.name}</option>
</Fragment>
))}
<Input
type="select"
id="country"
name="country"
className="mb-3"
value={country}
onChange={handleChange} <--- this calls update state and updates correctly but the select option wont render the correct country.name.
>
{numberCountries.map((country, index) => (
<Fragment>
<option key={index} value={JSON.stringify(country)}>{country?.name}</option>
</Fragment>
))}
</Input>
Here is the numberCountries thats being mapped over for the options
[
{
name: 'United States',
countryCode: 'US',
areaCodes: AreaCodes,
type: {
local: {
amount: '400'
},
toll_free: {
amount: '400'
},
}
},
{
name: 'Australia',
countryCode: 'AU',
type: {
local: {
amount: '1500'
},
}
},
{
name: 'Belgium',
countryCode: 'BE',
type: {
local: {
price: '410'
},
}
}
]
Instead of converting the whole country object to a string, you should use the countryCode property as its value.
Its not advised to use the index of an array as the key, so if you can use the countryCode as its key aswell.
<Input
type="select"
id="country"
name="country"
className="mb-3"
value={country.countryCode}
onChange={handleChange}
>
{numberCountries.map(({ countryCode, name }) => (
<Fragment>
<option key={countryCode} value={countryCode}>{name}</option>
</Fragment>
))}
</Input>
And then your handleChange function should be
const handleChange = async (event) => {
const obj = numberCountries.find(country => country.countryCode === event.target.value);
setCountry(obj);
};
Just remove setCountry(obj) in the handleChange
I am new to React. I'm using react-select and I've used the following code. The dropdown is displayed but I'm unable to see names and unable to view after selecting.
<Select
variant="outlined"
margin="normal"
fullWidth
value={this.state.selected}
options={RewardAutomationsList}
name="selected"
onChange={this.handleChange}
placeholder='None'
>
{RewardAutomationsList.map((option) => (
<option key={option.id} value ={option.name} label={option.name}>
{option.name}
</option>
))}
</Select>
handleChange = event => {
this.setState({
selected: event.name
});
};
The RewardAutomationsList looks like this:
RewardAutomationsList:
0:{name: "TEST 1 (INR 100)", id: "123"}
1:{name: "test 2 (INR 250)", id: "456"}
Can someone help with this?
same npm package use like this block code.
import React, { Component } from 'react'
import Select from 'react-select'
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' }
]
const MyComponent = () => (
<Select options={options} />
)
react-select accepts an array of objects having label and value keys. Your option objects in RewardAutomationsList have id and name keys, so it can't be displayed. You need to change them.
Also, when you subscribe to change events with react-select's onChange prop, the callback function you provide receives the selectedOption, not the event.
The following should work:
const RewardAutomationsList = [
{ label: "TEST 1 (INR 100)", value: "123" },
{ label: "test 2 (INR 250)", value: "456" },
];
class App extends React.Component {
state = {
selected: null,
}
handleChange = (selectedOption) => {
this.setState({
selected: selectedOption,
});
};
render() {
return (
<React.Fragment>
<Select
fullWidth
margin="normal"
name="selected"
onChange={this.handleChange}
options={RewardAutomationsList}
placeholder="None"
value={this.state.selected}
variant="outlined"
/>
{/* It's not necessary and it's only here to show the current state */}
<pre>{JSON.stringify(this.state, null, 2)}</pre>
</React.Fragment>
);
}
}
I have this component:
import React from 'react';
const options = [
{ label: "Lifestyle", value: "lifestyle"},
{ label: "Area", value: "area" },
{ label: "Random", value: "random" }
];
const ChannelCategory = props =>
props.visible ? (
<div>
{props.title}
<ul>
{options.map((option) => (
<li key={option.value}>
<label>
{option.label}
<input
className={props.className}
name={props.name} // need to be different
selected={props.selected === option.value} // e.g. lifestyle === lifestyle
onChange={() => props.onChange(option.value)}
type="radio"
/>
</label>
</li>
))}
</ul>
</div>
) : null;
export default ChannelCategory;
I am rendering it on another page here in a .map:
let displayExistingChannels = null;
if (channels !== null){
displayExistingChannels = (
channels.map(channel => {
return (
<Grid key={channel.key} item style={styles.gridItem} justify="space-between">
<ChannelListItem
channel={channel}
isSaving={isSaving}
onDeleteChannelClick={onDeleteChannelClick}
key={channel.key}
onFormControlChange={onFormControlChange}
onUndoChannelClick={onUndoChannelClick}
/>
{channel.category}
<ChannelCategory
visible={true}
onChange={value => setCategoryName(value)}
title="Edit Category"
selected={channel.category}
name={channel.key} // unique for every channel
/>
</Grid>
)
})
)
}
I am using fake data for the map:
const fakeChannelData = setupChannels(
[{id: "2f469", name: "shopping ", readOnly: false, category: "lifestyle"},
{id: "bae96", name: "public", readOnly: true, category: "null"},
{id: "06ea6", name: "swimming ", readOnly: false, category: "sport"},
{id: "7e2bb", name: "comedy shows ", readOnly: false, category: "entertainment"}]);
const [channels, setChannels] = useState(fakeChannelData);
Please can someone tell me why when I add selected={channel.category} in my .map function it does not show the selected category preselected on the FE on page load? Not sure where I have gone wrong? Thanks!
checked is the correct attribute to use for input tag, not selected.
<input
...
checked={props.selected === option.value}
...
/>
ref: https://developer.mozilla.org/fr/docs/Web/HTML/Element/Input/radio
I am trying to update my state from my react dynamically, this is my current state.
this.state = {
title: "",
image: "",
imageFile: "",
formTitle: "",
formMessage: "",
formImage: "",
Item: {
name: "Name",
price: "",
quantity: "",
discount: "",
shipping: "",
image: "",
formType: ""
}
}
How do I update in my Textbox dynamically instead of one by one?
setItemName = (name) => {
this.setState({
Item: {
...this.state.Item,
name
}
});
};
this is my attempt at solving this
and this is my Textbox using material UI
<TextField
className="my-24"
label="Item Name"
autoFocus
id="itemName"
name="itemName"
width={1}
value={this.state.Item.name}
onChange={this.setItemName}
variant="outlined"
/>
Thanks!!
As I understand from your doubt, you want to change the fields in state dynamically instead of writing the functions one by one....
setItemName = (changedValue, type) => {
this.setState({
Item: {
...this.state.Item,
[type]: changedValue
}
});
};
And your TextField going to be...
<TextField
className="my-24"
label="Item Name"
autoFocus
id="itemName"
name="itemName"
width={1}
value={this.state.Item.name}
onChange={(changedValue) => this.setItemName(changedValue, 'name')}
variant="outlined"
/>
You just need to pass the state field name in the setItemName argument.
As for 'price' you need to write setItemName(changedValue, 'price')
And nevermind,
I solve this,
This is my code for reference:
setItemValue = (field,value) => {
console.log(field,value)
this.setState(prevState => ({
Item: { // object that we want to update
...prevState.Item, // keep all other key-value pairs
[field] : value // update the value of specific key
}
}))
setItem = (key, value) => {
this.setState({
Item: {
...this.state.Item,
[key]: value
}
});
});
You can also try the following code
handleChange = e => {
this.setState({
Item: {
...this.state.Item,
[e.target.name]: e.target.value
}
});
Use name attribute as your state key :
<TextField
rowsMax={4}
placeholder="Enter name"
value={name}
name="name"
onChange={this.handleChange}
/>