React Select mapping issue - javascript

I'm using react-select in my project and I'm using it within a map like that:
renderItems() {
this.props.items.map(item => (
<Select
id="options"
value={this.state.optionSelected}
onChange={this.onChangeOption}
options={this.showOptions()}
/>
);
}
It show correctly all my options for all my items but now I can not get rid about the select...
Basically when I select an option on a single item, that option is changing for all items...
This is what i did so far:
onChangeOption(e) {
this.setState({ optionSelected: e.value });
}
How can I adjust it to change the option only on the one I wish to change it?
Thanks

You are using the same change handler for all of your select components and then set the same state value for all your select components. To deal with this either you need to separate your select components with a container component that handles their own state and change event or you need to give each select component a unique state value.
Example
renderItems() {
this.props.items.map(item => (
<Select
id="options"
value={this.state.optionSelected[item.id]}
onChange={(event) => this.onChangeOption(event, item.id)}
options={this.showOptions()}
/>
);
}
onChangeOption(event, itemId) {
this.setState((prevState) => {
const prevStateClone = Object.assign({}, prevState);
prevStateClone.optionSelected[itemId] = event.target.value;
return prevStateClone;
});
}

Instead of making optionSelected string variable, make it as array in state.
Now do the following.
renderItems() {
this.props.items.map(item, index => (
<Select
id="options"
value={this.state.optionSelected[index]}
onChange={(selectedValue) => this.onChangeOption(selectedValue, index)}
options={this.showOptions()}
/>
);
}
onChangeOption(selectedValue, index) {
const optionSelected = this.state.optionSelected.slice() // slicing to get new copy of optionSelected instead of referencing to old one which causes mutation
optionSelected[index] = selectedValue
this.setState({optionSelected: optionSelected})
}
What you were doing is using a single variable to hold values of the select box. So if anyone changes, it will reflect all select box

Try cloning the object to a new object or if this optionSelected is a class, you can implement a constructor that clones it for your like:
export class optionSelectedClass {
myfield = '';
constructor(fields){
this.myField = fields.myField;
}
}
or even
export class optionSelectedClass {
myfield = '';
constructor(fields){
for (let f in fields) {
if (!this[f]) {
this[f] = fields[f];
}
}
}
}

Related

React <select> automatic change does not trigger onChange

In my page, I have two <select> elements, where the options of the second one depends on the value of the first one.
In this case, the "problem" is that the options for a certain value in the first select are different from the options given when the first select has another value. Basically:
Alfa Romeo
Giulietta
Mito
Porsche
Cayenne
911
I've created a simple fiddle just to show you the example, and the problem: https://codesandbox.io/s/select-autochange-7bfj6
Please, open the console to see what I'm talking about. So, basically, at start 'Porsche' and '911' are selected. Then, if I change '911' to 'Cayenne' everything is good.
The problem is when I change 'Porsche' to 'Alfa': as it should be, the second select changes its value to 'Giulietta', BUT the onChange event of the second select is not triggered.
I'm mostly sure that the problem is some kind of de-synchronization between UI and state: in the state, the secondselect still has the value '911', but since that option is no longer available in the second select, it autoselect the first possible value.. But that autoselection is just "graphical".
I know this could be fixed by adding a "null" value in the second select, with the option <option value={''} label={'Select a Model'} />. But I'd like to mantain the autoselection when the first select changes.
EDIT: actually, the fix I proposed is not an actual fix: that 'select a Model' options has the value '', but the handleSelectSelectChange is still not triggered, so, while the UI selected value is '', in the state I still have '911'
React.useEffect(()=> {
if (!secondOptionsMemoized.some(x=> x === secondSelectValue)) {
console.log('Second Select Change in useEffect');
setSecondSelectValue(secondOptionsMemoized[0]);
}
}, [secondSelectValue, secondOptionsMemoized]);
You can use useEffect instead of useMemo and another state which set the second options:
import React, { useEffect } from "react";
import "./styles.css";
export default function App() {
const alfaForSecondOptions = ["Giulietta", "Mito"];
const otherForSecondOptions = ["Cayenne", "911"];
const [firstSelectValue, setFirstSelectValue] = React.useState("Porsche");
const [secondSelectValue, setSecondSelectValue] = React.useState("911");
const [secondOptions, setSecondOptions] = React.useState(
otherForSecondOptions
);
useEffect(() => {
console.log(secondSelectValue);
}, [secondOptions]);
useEffect(() => {
if (firstSelectValue === "Alfa") {
setSecondOptions(alfaForSecondOptions);
setSecondSelectValue("Giulietta");
} else {
setSecondOptions(otherForSecondOptions);
setSecondSelectValue("911");
}
}, [firstSelectValue]);
const handleFirstSelectChange = (e) => {
console.log("First Select Change", e.target.value);
setFirstSelectValue(e.target.value);
};
const handleSecondSelectChange = (e) => {
console.log("Second Select Change", e.target.value);
setSecondSelectValue(e.target.value);
};
return (
<div className="App">
<label>
<p>Brand</p>
<select onChange={handleFirstSelectChange} value={firstSelectValue}>
<option value={"Alfa"} label={"Alfa"} />
<option value={"Porsche"} label={"Porsche"} />
</select>
</label>
<label>
<p>Model</p>
<select onChange={handleSecondSelectChange} value={secondSelectValue}>
{secondOptions.map((x) => {
return <option key={x} value={x} label={x} />;
})}
</select>
</label>
</div>
);
}

Selected drop down value is not being updated in the drop down menu in React when there is a function call in onChange()

I am working on a filter that will fetch the data from serviceNow depending on what the user has selected in the drop down menu. In my onChange(), I have a function call that will be filtering the data based on the value returned by onChange(). However, as soon as I put the function call(handleFilter()), the result is correctly fetched and displayed but the drop down menu selection is not updated.
Here is my drop down menu snippet
export default function DropDownComponent(props) {
return (
<div className="DropDownBox">
<Select
defaultValue={props.options[0]}
isSearchable={false}
name="DropDownBox"
options={props.options}
styles={dropDownStyles}
autosize={false}
onChange = {
val => {
props.changeDropdownValue(val);
props.handleFilter(val)
}
}
/>
<div className="caret_down_centered" />
</div>
);
props.handleFilter(val) is the function call that prevents the updated in the drop down. If I remove this, then the drop down selection is updated but the whole functionality is rendered useless because there is no filtering being done.
handleFilter(val) is a parent class method & is simply invoking different API's depending upon what the value of val is which is passed from onChange(). I have no idea why it is interfering with the drop down menu.
I read that we can use a state and update the state everytime there is a change in selection but since I have a functional component, I am not sure how that will go.
I was not sure if handleFilter() code is needed here since it is a long code but if needed, then please let me know. I will post it here.
Try this:
const DropDownComponent = props => {
return (
<select
name="selectFieldName"
value={props.value}
onChange={props.handleChange}
// rest...
>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
</select>
)
}
class Parent extends React.Component {
// initial setup
constructor(props) {
super(props)
this.state = {
value: 2 // Set your default value
}
}
handleFilter = (value) => {
// Here you fetch the data using 'value' argument
console.log(value)
}
handleChange = e => {
const value = e.target.value
// update value
this.setState({
value // no need to write 'value' because both have the same name
})
// Call handleFilter passing selected "value"
this.handleFilter(value)
}
render() {
return (
<div>
{/* Passing value and handleChange */}
<DropDownComponent
value={this.state.value}
handleChange={this.handleChange}
/>
<p>Value {this.state.value}</p>
</div>
)
}
}
ReactDOM.render( <Parent / > , document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.6.2/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/15.6.2/react-dom.min.js"></script>
<div id="root"></div>
I guess your problem is calling handleFilter method in wrong place. Also, you didn't tell how you have set the selected value inside the handleFilter method. See this codeSandbox for example.

React-Select trigger selection of option

I have a react component with a <Select options={myoptions} onChange={this.mychangehandler}/> element from react-select. I have saved some settings using redux that can be accessed e.g. using this.props.myreducer.dropdownvalue(already tested, the values are available when first rendering the component)
Depending on the redux props I want to automatically select one of the options in the dropdown. How can I tell the <Select.../>dropdown to automatically select option 2 if this.props.myreducer.dropdownvalue is equal to 1?
There are countless properties but somehow I found no one that can help me automatically select the proper entry.
Any ideas? Solutions that will automatically trigger onChange as well prefered, but should be no problem if not.
Thanks in advance :)
Regards Christian
edit: Here is the full code:
import React, {Component} from 'react';
import { connect } from 'react-redux';
import Auxiliary from '../../../../../../../hoc/Auxiliary/Auxiliary';
import classes from './Dropdown.module.css';
import Select from 'react-select';
class Dropdown extends Component {
changeSetting = (event) => {
console.log('qid'+this.props.qid)
console.log('event: '+JSON.stringify(event))
if(this.props.certs.certquestions[this.props.qid].red === event.id)
{
this.props.colorchanger("red")
}else if(this.props.certs.certquestions[this.props.qid].yellow === event.id)
{
this.props.colorchanger("yellow")
}else if(this.props.certs.certquestions[this.props.qid].green === event.id)
{
this.props.colorchanger("green")
}
}
render(){
const options = []
const qid = this.props.qid
console.log('qid:'+qid)
const question = this.props.certs.certquestions[qid]
const opt = question.options.split("|")
for(let i = 0;i<opt.length;i++){
let optname = opt[i]
options.push({value:i, label:optname, id:i})
}
let notes = "";
let selectedOption = null;
if(this.props.loadp)
{
let progress = this.props.certs.loadedProgress[this.props.users.users[this.props.users.currentuser].target_id+'_'+this.props.q]
if (typeof progress !== 'undefined')
{
notes = progress.notes
selectedOption = progress.selectedOption
}
}
return(
<Auxiliary>
<h3>{question.title}</h3>
<Select className = {classes.Dropdown} options={options} onChange={this.changeSetting}/ value={selectedOption}> //selectedOption is an Integer
<textarea value = {notes}/>
</Auxiliary>
)
}
}
const mapStateToProps = state => {
return {
certs: state.certs,
users: state.users
};
}
export default connect(mapStateToProps, null)(Dropdown);
the options have different labels and value and id from 0 to 9. I tried to add value={selectedOption} to the Select element, also tried it with the label instead, but it always only shows the "Select..." placeholder and doesn't select the option and trigger the onChange. Any idea what I'm doing wrong?
Solved: I now know what I did wrong, thanks a lot :) I needed to pass an object with value, id and label to value :)
I needed to pass an object like this: {"value":0,"label":"v1","id":0} to value

:selected state on looped react component

I am basically wanting to do individual selected states on divs that I am rendering in a loop. I can only see a way to change the color of all of the rendered divs, but rather I wish to change the color of which ever one was clicked. Below is the code for the loop.
renderSports() {
const {sports} = this.props
return sports.valueSeq().map(sport => this.renderActualSports(sport))
},
renderActualSports(sport) {
const {sportCount} = this.props
return (
<div className="sportSeparator">
{sport} {this.renderCount(sportCount.get(sport))}
</div>
)
},
This will basically just render a list of some sports. I want to change the color of a selected sport on click.
You will need to store the items that were clicked in your component state.
Assuming you would store this highlighted items in this.state.highlighted and that your sport variable is a string or number:
renderActualSports(sport) {
const {sportCount} = this.props
return (
<div
className="sportSeparator"
onClick={this.highlight(sport)}
style={{color: this.state.highlighted.indexOf(sport) > -1 && 'red' : ''}}
>
{sport} {this.renderCount(sportCount.get(sport))}
</div>
)
},
highlight(sport) {
return () => {
this.setState({highlighted: [...this.state.highlighted, sport]});
}
}
So what you are doing is onClick on the div you add that sport to the this.state.highlighted array and when displaying the list. you check if that sport is in the array and if yes you change the color using an inline style

Get selected option text using react js?

I have my select list component rendering my select list:
<form className="pure-form">
<select ref="selectMark" className="mark-selector"
onChange={this.onChange}>{this.getOptions()}
</select>
</form>
I have a method on the component to create the options:
getOptions: function () {
return this.props.renderProps.data.map(function (item) {
return <option key={item.value} value={item.value}>{item.label}</option>;
}.bind(this));
},
My onChange method works fine with the value:
onChange: function(event) {
var newValue = event.nativeEvent.target.value;
this.props.renderProps.onSaveCare(newValue);
this.setState({value: newValue});
this.toggleEdit();
},
Is there a way I can get the option text? This gives me undefined
event.nativeEvent.target.text; //undefined
Something like this should do
var index = event.nativeEvent.target.selectedIndex;
event.nativeEvent.target[index].text
Here is a demo http://jsbin.com/vumune/4/
You can get the option text by replacing this:
event.nativeEvent.target.text;
with this:
event.target.options[event.target.selectedIndex].text
If it's single select, here is more simple way:
e.target.selectedOptions[0].text
This worked for me
const {options, value} = e.target;
console.log(options[value].innerHTML);
Edit: I just realized I was using the "value" field to store the ID of some objects, from 0 to n. I guess a better approach could be the following:
const {options, selectedIndex} = e.target;
console.log(options[selectedIndex].innerHTML);
The text of an option is simply the label property of the corresponding item.
In your case, to retrieve the text of the selected option, you can do:
var selectedItem = this.props.renderProps.data.find(function (item) {
return item.value === event.target.value;
});
selectedItem.label;
Array.prototype.find is part of the ES6 proposal. Underscore or lodash already package it as the _.find method.
Here what i do to retrieve the text from select option in react js.
this.refs.selectMark[this.refs.selectMark.value].text
It's easy using refs.
import the hook
import React, { useContext, useState, useEffect, useRef } from "react";
instantiate it
const yourNewRef= useRef();
Reference it in your element
ref={yourNewRef}
Then you can access it in any event or function by simply calling:
let textSelectOption = yourNewRef.current.options[yourNewRef.current.selectedIndex].text
You can access the value simply by calling
let optionValue = yourNewRef.current.value
refs are great, you can do almost everything you would using jQuery.
Take a look at yourNewRef on console and access all the content via the .current property
2020 and this Worked For Me
My Select Element :
<FormGroup>
{<Select
closeMenuOnSelect={true}
components={animatedComponents}
options={Options}
value = "Ahmedabad"
onChange={this.handleChange}
name = "citySelect"
/>}
</FormGroup>
Call handler :
handleChange = (e) => {
console.log(e.value)
}
change your menu item accordingly
Current / Temporary address
Permanent address
Office / Business Address
and on change event get
onChange = {(e,index) =>
( setAddressChangeType(e.target.value), console.log(index.props.id) )
}
make your dropdown accordingly and get value on change event like
onChange = {(e,index) =>
( setAddressChangeType(e.target.value), console.log(index.props.id) )
}

Categories