I have two working react-select drop downs on my page, one that allows the user to select A or B, and one that allows them to choose multiple items from "blue, yellow , red".
When they have chosen these items, I want to use them. For now I just want to check the values that have been selected, so I'm just printing them to screen. For the single selection drop down I have used the example code from the github successfully. This is as follows:
import React from 'react';
import Select from 'react-select';
const options = [
{ value: 'a', label: 'a' },
{ value: 'b', label: 'b' },
];
class App extends React.Component {
state = {
selectedOption: null,
}
handleChange = (selectedOption) => {
this.setState({ selectedOption });
document.write(`Option selected:`, selectedOption.value); //this prints the selected option
}
render() {
const { selectedOption } = this.state;
return (
<Select
value={selectedOption}
onChange={this.handleChange}
options={options}
//isMulti //added when the user can pick more than one
/>
);
}
}
My question is how do I successfully do this for the multi option? The user can select as many as they wish, but an 'undefined' error is thrown when it prints the option that has been selected. I think this is because the option is stored in an array but I'm not sure.
Thanks all.
You need to change the handleChange to deal with the isMulti. Here's an example:
import React, { Component } from 'react';
import { render } from 'react-dom';
import Select from 'react-select';
const options = [
{ value: 'a', label: 'a' },
{ value: 'b', label: 'b' },
];
class App extends React.Component {
state = {
selectedOptions: [],
}
handleChange = (selectedOptions) => {
this.setState({ selectedOptions });
}
render() {
const { selectedOptions } = this.state;
return (
<React.Fragment>
<Select
isMulti
value={selectedOption}
onChange={this.handleChange}
options={options}
/>
{selectedOptions.map(o => <p>{o.value}</p>)}
</React.Fragment>
);
}
}
render(<App />, document.getElementById('root'));
Here's a working example: https://stackblitz.com/edit/react-czf4ib
If you are using react hooks, here is how you can get the selected values from the react-select with isMulti prop.
import React, {useState} from 'react';
import Select from 'react-select';
import { useForm } from 'react-hook-form';
import { handleSubmit } = useForm();
const options = [
{ value: 'a', label: 'a' },
{ value: 'b', label: 'b' },
];
const FormComponent = (props) => {
const [selectedOptions, setSelectedOptions] = useState([]);
const handleChange = (options) => {
setSelectedOptions(options);
};
const onSubmit = (formData, event) => {
console.log("Form Data: ", formData)
console.log("Selected Options: ", selectedOptions)
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Select
isMulti = {true}
options={options}
closeMenuOnSelect={false}
onChange={handleChange}/>
<button type="submit">Save</button>
</form>
);
}
Hope it helps!
For store value in array try this one
[ "purple", "red", "blue" ]
handleChange = (selectedOptions) => {
let catArray = [];
selectedOptions.map(o =>
catArray.push(o.value)
);
this.setState({selectedOptions:catArray});
}
onChange={this.handleChange}
Related
Sorry for my bad english, i'm from Argentina.
I need to manage an array of checkboxes to make a filter. I'm working in a fictional rental car web (I'm still learning, it's a practice), and I want that when I check one or more checkboxes, it only show the cars with those characteristics. Car characteristics are un a .json file (api call).
This is the array of checkbox I've created to map and display in the layout.
export const features = [
{ name: "Manual Transmission", checked: false },
{ name: "5 seats", checked: false },
{ name: "Convertibles", checked: false },
{ name: "Automatic Transmission", checked: false },
{ name: "7 seats or more", checked: false },
];
And this is the component "Filter"
import { useContext, useEffect, useState } from "react";
import { v1 as uuidv1 } from "uuid";
import { features } from "../../utils/features";
import "./styles.css";
import { FilterContext } from "../../contexts/FilterContext";
import useInput from "../../hooks/useInput";
import { Carlist } from "../CarList";
export const Filter = () => {
const carsData = useContext(FilterContext);
const [filteredCars, setFilteredCars] = useState([]);
const [select, handleSelect] = useInput();
const [checkedValues, setCheckedValues] = useState([]);
const handleChecked = (e) => {
};
/* const featuresList = carsData.map((data) => data.Features2);
const featuresArray = Object.keys(featuresList).map(function (key) {
return featuresList[key];
}); */
useEffect(() => {
const filterSelect = carsData.filter((car) =>
car.VehGroup.includes(select)
);
setFilteredCars(filterSelect);
}, [select, carsData, checkedValues]);
return (
<div className="search-container">
<div className="filter-container">
<div className="filter-select-container">
<h2>Filter by</h2>
<select
className="filter-select"
onChange={handleSelect}
value={select}
>
<option value="">All</option>
{carsData.map((data) => (
<option key={uuidv1()} value={data.VehGroup}>
{data.VehGroup}
</option>
))}
</select>
</div>
<div className="filter-checkbox-container">
{features.map((carFeature) => {
return (
<div key={carFeature.name} className="filter-checkbox">
<input
onChange={handleChecked}
name={carFeature.feature}
type="checkbox"
/>
<label htmlFor={carFeature.feature}>{carFeature.name}</label>
</div>
);
})}
</div>
</div>
<Carlist carsData={filteredCars} />
</div>
);
};
CardList:
import "./styles.css";
import { v1 as uuidv1 } from "uuid";
import { CardCard } from "../CarCard";
export const Carlist = ({ carsData }) => {
return (
<div className="carList-container">
{carsData.map((data) => (
<CardCard
airConditionInd={data.AirConditionInd}
code={data.Code}
features2={data.Features2}
name={data.Name}
pictureURL={data.PictureURL}
rates={data.Rates}
vehGroup={data.VehGroup}
key={uuidv1()}
/>
))}
</div>
);
};
.JSON
https://api.npoint.io/3c713cdde915d38fd6aa
On your handledChecked function you should make it add the checked element to your filteredCars state by pushing the new value to this state.
setFilteredCars(oldArray => [...oldArray, newElement]);
newElement could be an object since your main array is array of objects.
import { Fragment, useState } from "react";
import Select from 'react-select';
let items = [
{
item: 1,
name: "tv"
},
{
item: 2,
name: "PC"
}
]
const Home = () => {
const [selectedValue, setSelectedValue] = useState(6)
const handleChange = obj => {
setSelectedValue(obj.item)
}
return (
<Fragment>
<div>Home page</div>
<p>Test React Select...</p>
<Select
value={items.find(x => x.item === selectedValue)}
options={items}
onChange={handleChange}
/>
<p>selected Value:...</p>
{selectedValue}
</Fragment>
)
}
export default Home;
you can pass the mapped array to "options" property:
options={items.map(({item, name}) => ({value: name, label: item}))}
I have multiple Select fields in my App component. Since it throws an error if I pass the event object(to access 'id' of each component) as a second parameter to the event handler(along with selectedOptions), I cannot have a single event handler for all the Select components. Instead, I currently need a separate event handler for each component, so that I can store the selected options of each component in different arrays in component state. If I could use event.target.id, I could do the same job with just one function.
codesandbox: https://codesandbox.io/s/peaceful-spence-1j3nv?fontsize=14&hidenavigation=1&theme=dark&file=/src/App.js
import React from 'react'
import Select from 'react-select';
const options = [
{ value: 'red', label: 'red' },
{ value: 'blue', label: 'blue' },
{ value: 'green', label: 'green' }
];
class App extends React.Component {
state = {
selectedOptionsFIRST: [],
selectedOptionsSECOND: [],
}
handleChangeFIRST = (selectedOptions) => {
this.setState({ selectedOptionsFIRST: selectedOptions });
}
handleChangeSECOND = (selectedOptions) => {
this.setState({ selectedOptionsSECOND: selectedOptions });
}
render() {
return (
<React.Fragment>
<Select
id={0}
isMulti
value={this.state.selectedOptionsFIRST}
onChange={this.handleChangeFIRST}
options={options}
/>
{this.state.selectedOptionsFIRST.map(o => <p>{o.value}</p>)}
<Select
id={1}
isMulti
value={this.state.selectedOptionsSECOND}
onChange={this.handleChangeSECOND}
options={options}
/>
{this.state.selectedOptionsSECOND.map(o => <p>{o.value}</p>)}
</React.Fragment>
);
}
}
What about passing the state field in the handler?
import React from "react";
import Select from "react-select";
const options = [
{ value: "red", label: "red" },
{ value: "blue", label: "blue" },
{ value: "green", label: "green" }
];
class App extends React.Component {
state = {
selectedOptionsFIRST: [],
selectedOptionsSECOND: []
};
handleChange = (id, selectedOptions) => {
this.setState({ [id]: selectedOptions });
};
render() {
return (
<React.Fragment>
<Select
isMulti
value={this.state.selectedOptionsFIRST}
onChange={(e) => {this.handleChange('selectedOptionsFIRST',e);}}
options={options}
/>
{this.state.selectedOptionsFIRST.map((o) => (
<p>{o.value}</p>
))}
<Select
isMulti
value={this.state.selectedOptionsSECOND}
onChange={(e) => {this.handleChange('selectedOptionsSECOND',e);}}
options={options}
/>
{this.state.selectedOptionsSECOND.map((o) => (
<p>{o.value}</p>
))}
</React.Fragment>
);
}
}
export default App;
I'm trying to create a web-app with the front end in React and backend in Flask. I have a dropdown which gets populated by the flask JSON which is basically a list of companies. All total there are around 5 components, the first one is the App.js, second is the CompanySelection.js, the third one is the Chart.js where I want to return my graphs and all.
So in theCompanySelection.js when I change the dropdown selection the updated company name does not go into Charts.js, i.e. the other component. I guess when this part gets solved similarly I can pass the values from one component to the other easily.
These are my three code files:
App.js
import React from "react";
import { CompanyContextProvider } from "./context";
import Dropdown from 'react-dropdown';
import 'react-dropdown/style.css';
import Header from "./Header";
import CompanySelection from "./CompanySelection/CompanySelection.js";
import Charts from "./Charts/Chart.js";
import axios from 'axios';
class App extends React.Component{
state = {
companies: [],
firstCompany: {},
firstCompanyName: ''
};
componentDidMount() {
fetch('http://127.0.0.1:5001/algo/loc')
.then(res => res.json())
.then(data => {
this.setState({companies: data,
firstCompany: data[0],
firstCompanyName: data[0].value}, () =>
console.log(this.state.companies, this.state.firstCompany, this.state.firstCompanyName));
console.log('')
}).catch(function (error) {
console.log(error);
});
}
selectedValueHandler = (selectedValue) => {
this.setState({
firstCompanyName: selectedValue
})
}
render() {
const { selectedValue } = this.state.firstCompanyName;
console.log('change value',selectedValue)
return (
<div className="app">
<Header/>
<CompanySelection companies= {this.state.companies} selectedCompany={this.state.firstCompany} setSelectedCompany={this.state.firstCompanyName} selectedValueHandler = {this.selectedValueHandler}/>
<Charts companies= {this.state.companies} selectedCompany={this.state.firstCompany} setSelectedCompany={selectedValue}/>
</div>
);
}
} ;
export default App;
CompanySelection.js
import { h, render, Component} from 'preact';
import style from './style.css';
import { useContext } from "preact/hooks";
import { CompanyContext } from "../context";
class CompanySelection extends Component {
constructor(props)
{
super(props);
}
render(_, { value }) {
const companies = this.props.companies;
const selectedCompany = this.props.selectedCompany;
const setSelectedCompany = this.props.setSelectedCompany;
var onChange = (e) =>{
console.log("In on change");
this.setState({ value: e.target.value });
const setSelectedCompany = e.target.value;
console.log("Selected", e.target.value);
const companies = this.props.companies;
const selectedCompany = this.props.selectedCompany;
this.props.selectedValueHandler(e.target.value);
}
if (typeof companies !== 'undefined')
{
var options = companies.map((comp) =>
<option
key={comp.label}
value={comp.value}
>
{comp.label}
</option>
);
}
else {
var options = [{value: 'A', label: 'B'}].map((comp) =>
<option
key={comp.label}
value={comp.value}
>
{comp.label}
</option>
);
}
return (
<fragment class={style.fragment}>
<label class={style.label}> Company </label>
<select value={value} onChange={onChange} class={style.dropdown}>
{options}
</select>
</fragment>
);
}
}
render(<CompanySelection />, document.body);
export default CompanySelection;
Chart.js
import { h, render, Component } from 'preact';
import style from './style.css';
import { VictoryChart, VictoryLine, VictoryScatter, VictoryLabel} from 'victory';
import { useContext } from "preact/hooks";
import { CompanyContext } from "../context";
class Charts extends Component {
constructor(props)
{
super(props);
}
render(_, { value }) {
const companies = this.props.companies;
const selectedCompany = this.props.selectedCompany;
const setSelectedCompany = this.props.setSelectedCompany;
console.log('list of companies chart', companies)
console.log('chart input', setSelectedCompany)
if (typeof selectedCompany !== 'undefined') {
var comp = selectedCompany;
}
else {
var comp = '';
}
console.log("comp", comp);
return (
<fragment>
<div class={style.chart}>
<VictoryChart domain={[0, 10]}>
<VictoryLabel text={comp} x={225} y={30} textAnchor="middle"/>
<VictoryLine
style={{ data: { stroke: "blue", strokeWidth: 3 } }}
y={(d) => d.x}
/>
<VictoryScatter
symbol="star"
size={8}
style={{ data: { fill: "red" }}}
data={[{ x: 5, y: 5 }]}
/>
<VictoryScatter
symbol="circle"
size={8}
style={{ data: { fill: "red" }}}
data={[{ x: 7, y: 7 }]}
/>
</VictoryChart>
</div>
</fragment>
);
}
}
render(<Charts />, document.body);
export default Charts;
I have taken reference of this code from this stackoverflow post: How to pass data from one component to another component in onchange using React js
However when I see the output of this line of code: const { selectedValue } = this.state.firstCompanyName;
console.log('change value',selectedValue)
I get that change value undefined, which means the values are not getting passed on. I'm very new to react and haven't been able to solve this yet. Any help is much appreciated.
P.S. The components pass on well to the <CompanySelection..../>
However when I see the output of this line of code: const { selectedValue } = this.state.firstCompanyName;
console.log('change value',selectedValue)
It will be undefined, here you are trying to destructure selectedValue from a string firstCompanyName, as long as this.state.firstCompanyName is not an object with a key named selectedValue it will be undefined. Instead do this.
const selectedValue = this.state.firstCompanyName;
console.log('change value',selectedValue)`
I have a dynamic form in react-js and some of my elements are checkbox/radio that one of them have a text input binded to it.
for example the question is:
What is your favorite color?
and the answers are:
- red
- blue
- green
- OTHER
and OTHER answer have a text input in front of it for user to typing his custom answer in it.
How can I bind that checkbox/radio to the relevant input text and get its value?
form
If you use a newer version of React, try the state hook.
Something along the lines of
import React, { useState } from 'react';
function Example() {
const [color, setColor] = useState('');
return (
<div>
<select value={color}
onChange={(e) => setColor(value)}>
{ ['red', 'blue', 'green', 'OTHER'].map((c) => <option key={c} value={c}>{c}</option>)}
</select>
{color === 'OTHER' && <input type="text"></input>}
</div>
);
}
https://reactjs.org/docs/hooks-state.html
Using Material UI, I have used a similar solution like this to add an "Other" checkbox that is fillable:
import React from "react";
import ReactDOM from "react-dom";
import FormGroup from "#material-ui/core/FormGroup";
import FormControlLabel from "#material-ui/core/FormControlLabel";
import Checkbox from "#material-ui/core/Checkbox";
import TextField from "#material-ui/core/TextField";
import "./styles.css";
class App extends React.Component {
constructor() {
super();
this.state = {
options: ["red", "blue", "green", "other"],
filterOptions: ["red", "blue", "green"],
checkedValues: [],
otherValue: "other"
};
}
handleOther = () => event => {
let value = event.target.value;
this.setState({
otherValue: value
});
};
handleSaveOther = () => event => {
let newCheckedValues = [...this.state.checkedValues]; // make a separate copy of the array
let intersection = newCheckedValues.filter(x =>
this.state.filterOptions.includes(x)
);
let allValues = [...intersection, this.state.otherValue];
if (this.state.other) {
this.setState({
checkedValues: allValues
});
}
};
handleCheck = option => event => {
let value = event.target.value;
let checked = event.target.checked;
let newCheckedValues = [...this.state.checkedValues]; // make a separate copy of the array
let index = newCheckedValues.indexOf(value);
if (index !== -1) {
newCheckedValues.splice(index, 1);
this.setState({
checkedValues: newCheckedValues,
[option]: checked
});
} else {
this.setState({
checkedValues: [...this.state.checkedValues, value],
[option]: checked
});
}
};
render() {
const { options, checkedValues, otherValue } = this.state;
console.log(checkedValues);
return (
<div className="App">
<div style={{ width: "50%", margin: "0 auto" }}>
<FormGroup>
{options.map((option, i) => {
return (
<FormControlLabel
control={
<Checkbox
onChange={this.handleCheck(option)}
value={option === "other" ? otherValue : option}
color={"primary"}
/>
}
label={
option === "other" ? (
<TextField
id={"other"}
name={"other"}
value={this.state.otherValue}
fullWidth
onChange={this.handleOther()}
onBlur={this.handleSaveOther()}
/>
) : (
option
)
}
/>
);
})}
</FormGroup>
</div>
</div>
);
}
}
See working example here