so I have this issue I am trying to solve, with React.
Let's say I have an object like so:
"options": {
"open": {
"text": "Open (Risky)",
"description": "Filler text for open"
},
"wpa": {
"text": "WPAWPA2PSK (TKIP / AES)",
"description": "Filler text for wpa"
},
"wpa2": {
"text": "WPA2-PSK (AES) (Recommended)",
"description": "Filler text for wpa2"
}
}
And I have it setup that the object's value's "text" is used to populate option values in a select dropdown, like so:
const securityModeOptions = Object.values(securityMode.select.options);
{securityModeOptions.map((mode, index) =>
<option key={index} value={mode.text}>
{mode.text}
</option>
)}
What I would like to do is that whichever option value is selected, it's corresponding "description" is displayed in a div next to it, and the div changes based on whichever option is selected.
Thanks!
You can manage a state of the selected key, then grab the relevant entry from the options object via the key.
Something like this:
const options = {
open: {
text: "Open (Risky)",
description: "Filler text for open"
},
wpa: {
text: "WPAWPA2PSK (TKIP / AES)",
description: "Filler text for wpa"
},
wpa2: {
text: "WPA2-PSK (AES) (Recommended)",
description: "Filler text for wpa2"
}
};
class App extends React.Component {
state = { selectedOptionKey: "" };
onChange = ({ target }) => {
this.setState({ selectedOptionKey: target.value });
};
render() {
const { selectedOptionKey } = this.state;
const description =
options[selectedOptionKey] && options[selectedOptionKey].description;
return (
<div>
<select onChange={this.onChange}>
<option>Choose</option>
{Object.entries(options).map(([key, value]) => (
<option value={key}>{value.text}</option>
))}
</select>
<div>{description}</div>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"/>
You could keep the key of the selected option in state and show the description of this selected option.
Example
const options = {
open: {
text: "Open (Risky)",
description: "Filler text for open"
},
wpa: {
text: "WPAWPA2PSK (TKIP / AES)",
description: "Filler text for wpa"
},
wpa2: {
text: "WPA2-PSK (AES) (Recommended)",
description: "Filler text for wpa2"
}
};
class App extends React.Component {
state = {
options,
selected: Object.keys(options)[0]
};
onChange = event => {
this.setState({ selected: event.target.value });
};
render() {
const { options, selected } = this.state;
return (
<div>
<select onChange={this.onChange}>
{Object.keys(options).map(key => (
<option key={key} value={key}>
{options[key].text}
</option>
))}
</select>
<span>{options[selected].description}</span>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Related
I have a select tag containing the optgroup and option tags which is multiple.
When I select the items, the state is not updated and the onChange does not work.
I want the value of the option tag to be transferred to state when the item or items are selected !!!.
const FunctionalComponent = () => {
const [mystate , setMyState] = useState([]);
return(
<div>
<select
onChange={(e) => setMyState(e.target.value) }
className='form-control'
multiple='multiple'
value={mystate}
>
{datas.map((obj) => (
return (
<optgroup key={obj.title} label={obj.title}>
{obj.map((o) => (
<option key={o.id} value={o.id}>{o.name}</option>
))}
</optgroup>
);
))}
</select>
</div>
)
}
export default FunctionalComponent
Thanks to those who help me.
Without knowing how datas is structured it's difficult to write code for it, but based on how I think it's structured here some working code.
Intialiase state as an array.
Have your handler get the selectedOptions, and get each option's value. Add that array to your state.
Here datas is an array objects. Each one has a title, and another array of objects containing the option data. map over the main array, and then map over the options array.
const { useState } = React;
function Example({ datas }) {
const [mystate , setMyState] = useState([]);
function handleChange(e) {
const options = e.target.selectedOptions;
const values = Array.from(options, option => option.value);
setMyState(values);
}
return (
<div>
<select
onChange={handleChange}
className="form-control"
multiple="multiple"
value={mystate}
>{datas.map(obj => {
return (
<optgroup
key={obj.title}
label={obj.title}
>{obj.options.map(obj => {
return (
<option
key={obj.id}
value={obj.id}
>{obj.name}
</option>
);
})}
</optgroup>
);
})}
</select>
</div>
);
}
const datas = [
{
title: 1,
options: [
{ id: 1.1, name: 1.1 },
{ id: 1.2, name: 1.2 },
]
},
{
title: 2,
options: [
{ id: 2.1, name: 2.1 },
{ id: 2.2, name: 2.2 },
]
},
];
ReactDOM.render(
<Example datas={datas} />,
document.getElementById('react')
);
form-control { width: 200px; height: 200px}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>
I am trying to change the background color of select element based on which option user selects. I have created this example https://codepen.io/lordKappa/pen/YzrEWXd and here the color changes but it also changes for all select elements not just for the one we changed.
const [selectState, setSelectState] = useState("To-do");
const [taskID, setTaskID] = useState();
function handleDropdownChange(e) {
var taskID = e.currentTarget.getAttribute("data-index");
setTaskID(taskID);
setSelectState(e.target.value);
}
if (selectState === "To-do") {
selectStyle = {
backgroundColor: "red",
};
} else if (selectState === "Done") {
selectStyle = {
backgroundColor: "green",
};
} else {
selectStyle = {
backgroundColor: "yellow",
};
}
return (
<div className="box">
<div>
{elementList.map((task) => (
<div key={task.id}>
<h1>{task.info}</h1>
<select
onChange={handleDropdownChange}
data-index={task.id}
style={selectStyle}
>
<option value="To-do">To-do</option>
<option value="Done">Done</option>
<option value="In progress">In progress</option>
</select>
</div>
))}
</div>
</div>
);
};
The color changes an all dropdowns in the code-pen you provided because they all rely on the same piece of state. You either need to make the state for each dropdown be independent of each other, or separate the dropdown into its own component.
You should create a state for tasks
const [tasks, setTasks] = useState([
{ id: 0, info: "Task 1", status: 'TODO' },
{ id: 1, info: "Task 2", status: 'TODO' },
{ id: 2, info: "Task 3", status: 'TODO' }
]);
Then, everytime you change the selectbox, update status inside tasks state
function handleDropdownChange(e) {
var taskID = e.currentTarget.getAttribute("data-index");
setTasks(tasks.map(task => {
if (taskID !== task.id) return task;
task.status = e.target.value
return task
}));
}
Finally, when rendering tasks we only need to check the task's status and change style
{elementList.map((task) => {
// put your condition here ....
return (
<div key={task.id}>
<h1>{task.info}</h1>
<select
onChange={handleDropdownChange}
data-index={task.id}
style={selectStyle}
>
<option value="To-do">To-do</option>
<option value="Done">Done</option>
<option value="In progress">In progress</option>
</select>
</div>
)
})}
I have a radio button component and iam mapping api data to it what i want is whenever an option is selected my website should display some data let say some kind of description text the problem is the data does not change on button click it remains the same for every option selected.
This is my radio button and p tag below is where text is to be displayed
<input
type="radio"
title="giftCard"
value={this.state.giftCard}
name={this.props.giftDetails.variations.map(
(e) => e.reward_text
)}
onChange={(e) => {
this.setState({ giftCard: e.target.value });
}}
onClick={() => {
this.props.giftDetails.variations.map(
(e) => this.setState({ giftDescription: e.reward_description })
)
}}
/>
<p dangerouslySetInnerHTML={{ __html: giftDescription}}/>
my api respone is
"variations": [
{
"variation_id": 1,
"variation_name": "210kr",
"price": "210",
"reward_text": "200kr. Price",
"reward_description": "Med et gavekort til Sendentanke.dk kan du vælge mellem gavekort til hundredevis af butikker og oplevelser ét sted."
},
{
"variation_id": 2,
"variation_name": "400kro",
"price": "400",
"reward_text": "400 Price",
"reward_description": "Earn a reward"
}
],
You can see in the picture how radio buttons are added and how text is displayed
Remove onclick since you can handle the setState with onChange itself also use checked attribute for radio button and generate the radio buttons through iteration like below.
const Options = this.props.giftDetails.variations.map((v) => {
return (
<React.Fragment key={v.variation_id}>
<input
type="radio"
value={v.variation_id}
checked={v.variation_id == this.state.giftCard}
onChange={(e) => {
this.setState({
giftCard: e.target.value,
giftDescription: v.reward_description,
});
}}
/>
{v.reward_text}
</React.Fragment>
);
});
return (
<React.Fragment>
{Options}
<p>{this.state. giftDescription}</p>
</React.Fragment>
);
class Hello extends React.Component {
constructor() {
super();
this.state = { giftCard: null, giftDescription: null };
}
render() {
console.log("this.state", this.state);
const variants = {
variations: [
{
variation_id: 1,
variation_name: "210kr",
price: "210",
reward_text: "200kr. Price",
reward_description:
"Med et gavekort til Sendentanke.dk kan du vælge mellem gavekort til hundredevis af butikker og oplevelser ét sted.",
},
{
variation_id: 2,
variation_name: "400kro",
price: "400",
reward_text: "400 Price",
reward_description: "Earn a reward",
},
],
};
const Options = variants.variations.map((v) => {
return (
<React.Fragment>
<input
key={v.variation_id}
type="radio"
value={v.variation_id}
checked={v.variation_id == this.state.giftCard}
onChange={(e) => {
this.setState({
giftCard: e.target.value,
giftDescription: v.reward_description,
});
}}
/>
{v.reward_text}
</React.Fragment>
);
});
return (
<React.Fragment>
{Options}
<p>{this.state.giftDescription}</p>
</React.Fragment>
);
}
}
ReactDOM.render(<Hello name="World" />, document.getElementById("container"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
I am using antd library as part of react application. For select option values are fetched from api and rendered in this format.
<Select
{...propsForSelect}
>
{this.props.data.map(e =>
<Option
key={e.key || e}
value={e.value || e}
title={e.title}
>
{`${e.key} | ${e.value}`}
/Option>
)}
</Select>
Once user selects an option I want to display only the value and not {${e.key} | ${e.value}} value.
{${e.key} | ${e.value}} is displaying in dropdown and when user selects an option need to show e.value alone.
CodeSandbox: https://codesandbox.io/s/tender-feynman-uhtn7
Is this what you are looking for?
https://codesandbox.io/s/headless-river-1n0e3
Basically I just added a selected property to each genre object, and then in the Select component's onSelect() prop, passed a callback function that updates state and toggles the respective genre's selected property to true.
Then, in the UI, I simply check if the selected property is true for each genre and then conditionally render only the display value in that case.
This is what the optionLabelProp is for.
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import './index.css';
import { Select } from 'antd';
const { Option } = Select;
class App extends React.Component {
state = {
genres: [{"key": 1000, "value": "1", "display": "Action"},
{"key": 1001, "value": "2", "display": "Adventure"},
{"key": 1002, "value": "3", "display": "Comedy"}]
};
render() {
return (
<div className="container">
<Select
style={{width:"50%"}}
optionLabelProp="value"
>
{this.state.genres.map(e =>
<Option
key={e.key}
value={e.value}
>
{`${e.display} | ${e.value}`}
</Option>
)}
</Select>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('container'),
);
class App extends React.Component {
state = {
genres: [
{ key: 1000, value: "1", display: "Action" },
{ key: 1001, value: "2", display: "Adventure" },
{ key: 1002, value: "3", display: "Comedy" }
],
selected: '' // A default value can be used here e.g., first element in genres
};
handleChange = key => {
this.setState({ selected: this.state.genres.find((object) => object.key === Number(key)).value });
};
render() {
return (
<div className="container">
<Select value={this.state.selected} onChange={this.handleChange} style={{ width: "50%" }}>
{this.state.genres.map(e => (
<Option key={e.key}>
{`${e.display} | ${e.value}`}
</Option>
))}
</Select>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("container"));
We are using React-Select within our forms.
We would like to have a select dropdown that can never be blank (similar to include_blank: false in Rail's SimpleForm).
<Select
simpleValue={true}
id={input.name} {...input} {...inputHtml}
className={inputClass}
name="form-field-name"
value={value}
onChange={this.handleChange}
options={selectOptions}
multi={this.props.multi}
clearable={false}
/>
I am passing in options (which are appearing, and setting clearable to false, but the select field is still able to be blank. Is there a way to prevent the blank from even being an option?
If you ignore setting a selectedOption when you don't get an option to the onChange callback it will work as expected:
Example
class App extends Component {
constructor(props) {
super(props);
const options = [
{ value: "one", label: "One" },
{ value: "two", label: "Two" }
];
this.state = {
options,
selectedOption: options[0]
};
}
handleChange = selectedOption => {
if (selectedOption) {
this.setState({ selectedOption });
}
};
render() {
const { options, selectedOption } = this.state;
return (
<Select
value={selectedOption}
onChange={this.handleChange}
options={options}
clearable={false}
/>
);
}
}