I'm trying to get the 'key' value of my dynamic dropdown list as follows:
searchSubmit(e){
const s = e.target.value;
alert(s);
}
my dropdown list is as follows:
<select
className="textboxstyle"
onChange={this.searchSubmit}
>
<option key='-1'>Select Brand</option>
<option key='0'>ALL</option>
{optionItems}
</select>
And my dynamic drop-down is populated as follows,
let brands = this.state.brands;
let optionItems = brands.map((brand) =>
<option key={brand.id}>{brand.name}</option>
);
But when I select option, alert display the name of the selected value, not the key. How to get the 'key' value?
Thanks
The key prop is used by React to differentiate between all the elements in an array. If you want value to be the id of the brand, you can use it as value as well as key.
Example
class App extends React.Component {
state = {
brands: [{ id: 1, name: "Foo" }, { id: 2, name: "Bar" }]
};
searchSubmit = e => {
const { value } = e.target;
alert(value);
};
render() {
const { brands } = this.state;
return (
<select onChange={this.searchSubmit}>
<option value="-1">Select Brand</option>
<option value="0">ALL</option>
{brands.map(brand => (
<option value={brand.id} key={brand.id}>
{brand.name}
</option>
))}
</select>
);
}
}
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 select such as :
<Select id='1' list={[...this.state.dictionnary]}/>
where this.state.dictionnary is like this :
state = {
dictionnary: [
{value: "a", name: "ab"},
]}
And the component select is like this :
class Select extends Component {
handleChange()
{
// I would like to show 1, a and ab
// 1 is the id of the select
// a and ab are value and name of
};
render() {
return (
<select onChange={this.handleChange} className="custom-select">{this.props.list.map(option => (
<option key={option.value} value={option.value}>{option.name}</option>))}
</select>
)
}
}
export default Select;
I would like to show some informations using the handleChange() function like the id, name and value.
Could you help me please ?
Thank you very much
You should change the option so the value has the entire object to get it later in the handleChange. Also, to access the same this with the props in the handleChange method you need to use an arrow function:
<select onChange={(e) => this.handleChange} className="custom-select">
{this.props.list.map((option) => (
<option key={option.value} value={option}>
{option.name}
</option>
))}
</select>
By default, the onChange handler gets the event param so you can get the target and the props:
handleChange(event) {
const { value, name } = event.target.value;
console.log(this.props.id, value, name);
}
Adding to #Alavaro answer, you need to split after getting the value to remote ,
handleChange = e => {
const [value, name] = e.target.value.split(',')
console.log({ id: this.props.id, value, name})
}
render() {
return (
<select onChange={this.handleChange} className="custom-select">
{this.props.list.map((option, index) => (
<option key={option.value} value={[option.value, option.name]} >
{ option.name }
</option>
))}
</select>
);
}
}
The following is the simple react code containing two dropdowns to select report type and date type respectively. On selecting the each of the dropdowns, I try to update the respective single property (metricsDropDown : reporType, dateDropDown:dateType) in the state using spread operator. However the reportType is getting updated as undefined in state.
The code is given below:
class MetricsReport extends Component {
constructor(props) {
super(props)
this.state = {
metricsParams: {reportType: "", dateType: ""}
}
this.getReportType = this.getReportType.bind(this);
this.getMetricsDateType = this.getMetricsDateType.bind(this);
}
getReportType(event) {
console.log(this.state.metricsParams);
const {value} = event.target.value;
this.setState(prevState => ({
metricsParams: {
...prevState.metricsParams,
reportType: value
}
}))
}
getMetricsDateType(event) {
console.log('metricsparams:reportType', this.state.metricsParams.reportType); // reportType is undefined here
const {value} = event.target.value;
this.setState(prevState => ({
metricsParams: {
...prevState.metricsParams,
dateType: value
}
}))
}
componentDidMount() {
}
render() {
return (
<div >
<select id="metricsDropDown" className="browser-default" onChange={this.getReportType}>
<option value="MetricsByContent">Metrics By Content</option>
<option value="MetricsByUser">Metrics By User</option>
</select>
<select id="dateDropDown" className="browser-default" onChange={this.getMetricsDateType}>
<option value="Publish Date">Publish Date</option>
<option value="Expiry Date">Expiry Date</option>
<option value="Read Date">Read Date</option>
</select>
</div>
)
}
}
export default MetricsReport;
Destructuring syntax is wrong. It expects value property to be an object with another value property.
It should be:
const {value} = event.target;
var MySelect = React.createClass({
change: function(){
return document.querySelector('#lang').value;
},
render: function(){
return(
<div>
<select id="lang">
<option value="select" onChange={this.change}>Select</option>
<option value="Java" onChange={this.change}>Java</option>
<option value="C++" onChange={this.change}>C++</option>
</select>
<p></p>
<p value={this.change}></p>
</div>
);
}
});
React.render(<MySelect />, document.body);
The onChange event does not work.
The change event is triggered on the <select> element, not the <option> element. However, that's not the only problem. The way you defined the change function won't cause a rerender of the component. It seems like you might not have fully grasped the concept of React yet, so maybe "Thinking in React" helps.
You have to store the selected value as state and update the state when the value changes. Updating the state will trigger a rerender of the component.
var MySelect = React.createClass({
getInitialState: function() {
return {
value: 'select'
}
},
change: function(event){
this.setState({value: event.target.value});
},
render: function(){
return(
<div>
<select id="lang" onChange={this.change} value={this.state.value}>
<option value="select">Select</option>
<option value="Java">Java</option>
<option value="C++">C++</option>
</select>
<p></p>
<p>{this.state.value}</p>
</div>
);
}
});
React.render(<MySelect />, document.body);
Also note that <p> elements don't have a value attribute. React/JSX simply replicates the well-known HTML syntax, it doesn't introduce custom attributes (with the exception of key and ref). If you want the selected value to be the content of the <p> element then simply put inside of it, like you would do with any static content.
Learn more about event handling, state and form controls:
http://facebook.github.io/react/docs/interactivity-and-dynamic-uis.html
http://facebook.github.io/react/docs/forms.html
React Hooks (16.8+):
const Dropdown = ({
options
}) => {
const [selectedOption, setSelectedOption] = useState(options[0].value);
return (
<select
value={selectedOption}
onChange={e => setSelectedOption(e.target.value)}>
{options.map(o => (
<option key={o.value} value={o.value}>{o.label}</option>
))}
</select>
);
};
import React, { PureComponent, Fragment } from 'react';
import ReactDOM from 'react-dom';
class Select extends PureComponent {
state = {
options: [
{
name: 'Select…',
value: null,
},
{
name: 'A',
value: 'a',
},
{
name: 'B',
value: 'b',
},
{
name: 'C',
value: 'c',
},
],
value: '?',
};
handleChange = (event) => {
this.setState({ value: event.target.value });
};
render() {
const { options, value } = this.state;
return (
<Fragment>
<select onChange={this.handleChange} value={value}>
{options.map(item => (
<option key={item.value} value={item.value}>
{item.name}
</option>
))}
</select>
<h1>Favorite letter: {value}</h1>
</Fragment>
);
}
}
ReactDOM.render(<Select />, window.document.body);
handleChange(value, selectOptionSetter) => {
selectOptionSetter(value)
// handle other stuff like persisting to store etc
}
const Dropdown = (props) => {
const { options } = props;
const [selectedOption, setSelectedOption] = useState(options[0].value);
return (
<select
value={selectedOption}
onChange={e => handleChange(e.target.value, setSelectedOption)}>
{options.map(o => (
<option key={o.value} value={o.value}>{o.label}</option>
))}
</select>
);
};
If you are using select as inline to other component, then you can also use like given below.
<select onChange={(val) => this.handlePeriodChange(val.target.value)} className="btn btn-sm btn-outline-secondary dropdown-toggle">
<option value="TODAY">Today</option>
<option value="THIS_WEEK" >This Week</option>
<option value="THIS_MONTH">This Month</option>
<option value="THIS_YEAR">This Year</option>
<option selected value="LAST_AVAILABLE_DAY">Last Availabe NAV Day</option>
</select>
And on the component where select is used, define the function to handle onChange like below:
handlePeriodChange(selVal) {
this.props.handlePeriodChange(selVal);
}
I'll add this here, in case it helps someone because this was the solution that helped me.
This is to get the SELECTED INDEX. Not for the value.
(Worked for me because my options list was a list of numbers)
const [selectedOption, setSelectedOption] = useState(0)
<select onChange={event => setSelectedOption(event.target.options.selectedIndex)}>
Thank you Felix Kling, but his answer need a little change:
var MySelect = React.createClass({
getInitialState: function() {
return {
value: 'select'
}
},
change: function(event){
this.setState({value: event.target.value});
},
render: function(){
return(
<div>
<select id="lang" onChange={this.change.bind(this)} value={this.state.value}>
<option value="select">Select</option>
<option value="Java">Java</option>
<option value="C++">C++</option>
</select>
<p></p>
<p>{this.state.value}</p>
</div>
);
}
});
React.render(<MySelect />, document.body);
var MySelect = React.createClass({
getInitialState: function() {
var MySelect = React.createClass({
getInitialState: function() {
return {
value: 'select'
}
},
change: function(event){
event.persist(); //THE MAIN LINE THAT WILL SET THE VALUE
this.setState({value: event.target.value});
},
render: function(){
return(
<div>
<select id="lang" onChange={this.change.bind(this)} value={this.state.value}>
<option value="select">Select</option>
<option value="Java">Java</option>
<option value="C++">C++</option>
</select>
<p></p>
<p>{this.state.value}</p>
</div>
);
}
});
React.render(<MySelect />, document.body);
<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>