React: multiple selection (through Ctrl or Alt) - javascript

I can't select more than one value. How can I fix it?
import React from "react";
import ReactDOM from "react-dom";
class FlavorForm extends React.Component {
constructor(props) {
super(props);
this.state = { value: ["grapefruit", "coconut"] };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ value: [event.target.value] });
}
handleSubmit(event) {
alert("Your favorite flavor is: " + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Pick your favorite flavor:
<select
multiple={true}
value={this.state.value}
onChange={this.handleChange}
>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
ReactDOM.render(<FlavorForm />, document.getElementById("root"));

You'll need to get the value of all the currently selected options:
class FlavorForm extends React.Component {
constructor(props) {
super(props);
this.state = { value: ["grapefruit", "coconut"] };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
const value = Array.from(event.target.options) // get an array of all options
.filter(el => el.selected) // remove not selected
.map(el => el.value); // get the values
this.setState({ value });
}
handleSubmit(event) {
alert("Your favorite flavor is: " + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Pick your favorite flavor:
<select
multiple
value={this.state.value}
onChange={this.handleChange}
>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
ReactDOM.render(<FlavorForm />, document.getElementById("root"));
<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="root"></div>

You need to use e.target.options not e.target.value then loop through and return/setState with the selected options array:
Using forEach:
handleChange (e) {
const options = e.target.options;
let value = []
options.forEach((option)=> option.selected && value.push(option.value))
this.setState({ value })
}
Using reduce:
handleChange (e) {
const value = e.target.options.reduce((selected, option)=> option.selected ? [...selected , option.value] : selected , [])
this.setState({ value })
}

You need to also add a size attribute to your select element
<select
multiple={true}
value={this.state.value}
onChange={this.handleChange}
size={4}
>
would allow the user to select up to 4 options

Related

Getting undefined from a dropdown in React

I have read so many posts that i think I have read so many and got confused as it seems there are many ways to do what i need. This is my component
class InputForm extends React.Component {
constructor(props) {
super(props);
this.state = { dropdown: 'RTS', value: '' };
this.handleChange = this.handleChange.bind(this);
this.handleDropdown = this.handleDropdown.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ value: event.target.value });
}
handleDropdown(event) {
this.setState({ dropdown: event.target.dropdown });
}
handleSubmit(event) {
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit} className='flex'>
<select value={this.state.dropdown} onChange={this.handleDropdown} className='py-2 px-3 mr-2 rounded'>
<option value='RTS'>RTS</option>
<option value='RTB'>RTB</option>
<option value='BH'>BH</option>
<option value='MPC'>MPC</option>
<option value='MPC_DSP'>MPC_DSP</option>
</select>
<input
type='text'
value={this.state.value}
onChange={this.handleChange}
className='py-2 px-3 mr-2 rounded'
placeholder='Log Name...'
/>
<Btn onClick={() => getData(this.state.dropdown, this.state.value)}>Generate</Btn>
</form>
);
}
}
export default InputForm;
When changing the state of value={this.state.dropdown} i am getting undefined. Have i set everyting correctly?
In your handleDropdown function you need to retrieve the value from event.target.value instead of event.target.dropdown:
handleDropdown(event) {
this.setState({ dropdown: event.target.value });
}

Why do I get 'Error: Converting circular structure to JSON' with a label?

I have the following code, verbatim from the React docs:
class FlavorForm extends React.Component {
constructor(props) {
super(props);
this.state = { value: 'coconut' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
const { options } = event.target;
console.log(options)
this.setState({ value: event.target.value });
}
handleSubmit(event) {
alert('Your favorite flavor is: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Pick your favorite La Croix flavor:
<select value={this.state.value} onChange={this.handleChange}>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
<input type="submit" value="Submit" />
</label>
</form>
);
}
}
As it is, if I try console.log(options), I get the error:
Error: Converting circular structure to JSON.
However, moving the <label> tag up (so we have):
<label>Pick your favorite La Croix flavor:</label>
Allows the console.log() to work as intended.
Why does moving the label have this effect?
Working example here.
It seems that this is an issue with StackBlitz, as the same code works as expected on CodeSandbox and JSFiddle.

How handle multiple select form in ReactJS

I try to handle a multiple form select option, in ReactJS. I have tried to be inspire of javascript classic code to handle that, but I fail.
My code just don't send me the values selected. How handle that ?
Here my code :
class ChooseYourCharacter extends React.Component {
constructor(props) {
super(props);
this.state = {value: 'coconut'};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.option});
}
handleSubmit(event) {
alert('Your favorite flavor is: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Pick your favorite La Croix flavor:
<select multiple={true} value={this.state.value} onChange={this.handleChange}>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
ReactDOM.render(
<ChooseYourCharacter/>,
document.getElementById('root')
)
Of my basic understanding, when you try to handle a Select form element in reactJS you generates an object in HTMLOptionsCollection.
The fundamental root to this object methods and properties is e.target.options.
Your items are stored in e.target.options.value property.
To access to a value stored in the options.value object, you can use the [i] loop value, hence e.target.options[i].value property.
The e.target.options[i].value return strings data types.
Following what I have just said, I assume the objects are stored respecting a number increasing convention as following :
e.target.options[i].value where { [i] : value, [i +1] : value (...)}...
By using e.target.options[i].selected you can control if there is a value stored at a specific location.
e.target.options[i].selected return you a boolean value, useful to handle the code flow.
It's up to you now.
Here my code to handle multiple select form in JSX with javascript code :
// Create the React Component
class ChooseYourCharacter extends React.Component {
// Set the constructor
constructor(props) {
super(props);
this.state = {value: 'coconut'};
// bind the functions
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
// extract the value to fluently setState the DOM
handleChange (e) {
var options = e.target.options;
var value = [];
for (var i = 0, l = options.length; i < l; i++) {
if (options[i].selected) {
value.push(options[i].value);
}
}
this.setState({value: value});
}
// display in client-side the values choosen
handleSubmit() {
alert("you have choose :" + this.state.value);
}
(...)
Here is how to get the options selected by the user using a functional component and the useState hook rather than a class component:
import React, { useState } from "react";
const ChooseYourCharacter = function(props) {
const [selectedFlavors, setSelectedFlavors] = useState([]);
const handleSelect = function(selectedItems) {
const flavors = [];
for (let i=0; i<selectedItems.length; i++) {
flavors.push(selectedItems[i].value);
}
setSelectedFlavors(flavors);
}
return (
<form>
<select multiple={true} value={selectedFlavors} onChange={(e)=> {handleSelect(e.target.selectedOptions)}}>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
</form>
);
};
export default ChooseYourCharacter;
Currently learning React and I noticed this same code on the reactjs.org site. Below is my solution for handling multiple selected options.
in the constructor, use an array for the initial value for 'value' in the state
in the handleChange method, convert the event target's selectedOptions (HTMLOptionsCollection - array-like) to an array using Array.from(), and use a mapping function to get the value from each item
class ChooseYourCharacter extends React.Component {
constructor(props) {
super(props);
//this.state = {value: 'coconut'};
this.state = {value: ['coconut']};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
//this.setState({value: event.option});
this.setState({value: Array.from(event.target.selectedOptions, (item) => item.value)});
}
handleSubmit(event) {
alert('Your favorite flavor is: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Pick your favorite La Croix flavor:
<select multiple={true} value={this.state.value} onChange={this.handleChange}>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
ReactDOM.render(
<ChooseYourCharacter/>,
document.getElementById('root')
)
<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="root"></div>
As you are using multi-select you should declare your state variable as an array
constructor(props) {
super(props);
this.state = {value: []};//This should be an array
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
I have created a blog for reactjs form posting with multi select control. You may go here for more details https://handyopinion.com/git-commands-cheat-sheet/
I am using react bootstrap 4 here
<Form.Group >
<Form.Label>Form Label</Form.Label>
<Form.Control
as="select"
multiple
// value={formCatState}
onChange={(event) => {
let target = event.target as HTMLSelectElement
console.log(target.selectedOptions);
}}
>
<option>example cat 1</option>
<option>Example cat 2</option>
<option>Example cat 3</option>
<option>Example cat 4</option>
</Form.Control>
<Form.Text muted> hold ctrl or command for multiple select</Form.Text>
</Form.Group>

How to handle multiple input field changes by a single function

I have form in which 2 fields, and on click i want to save fields data into the state object.
I don't want to make different function for every input field on change.
Code:
import React, {Component} from 'react';
export default class Todo extends Component {
constructor(props){
super(props);
this.state = {
data : {
"name":'',
"option":'',
},
},
this.inputChange = this.inputChange.bind(this);
this.handleForm = this.handleForm.bind(this);
}
inputChange = (propertyName,e) => {
this.setState({});
}
handleForm = () => {
console.log(this.state.data);
console.log(this.state.data.name);
console.log(this.state.data.option);
}
render(){
return(
<div>
<form onSubmit={this.handleForm}>
<input type="text" placeholder="Enter text" name="name" value={this.state.data.name} onChange={this.inputChange.bind(this, "name")} />
<select name="option" value={this.state.data.option} onChange={this.inputChange.bind(this, "option")}>
<option> Select Option </option>
<option value="1"> Option 1 </option>
<option vlaue="2"> Option 2 </option>
</select>
<button type="submit"> Submit </button>
</form>
</div>
);
}
}
As per MDN DOC:
The object initializer syntax also supports computed property names.
That allows you to put an expression in brackets [], that will be
computed and used as the property name.
Use this:
inputChange = (propertyName,e) => {
let data = {...this.state.data};
data[propertyName] = e.target.value;
this.setState({ data });
}
Working Code:
class Todo extends React.Component {
constructor(props){
super(props);
this.state = {
data : {
"name":'',
"option":'',
},
},
this.inputChange = this.inputChange.bind(this);
this.handleForm = this.handleForm.bind(this);
}
inputChange = (propertyName,e) => {
let data = {...this.state.data};
data[propertyName] = e.target.value;
this.setState({ data });
}
handleForm = () => {
console.log(this.state.data);
console.log(this.state.data.name);
console.log(this.state.data.option);
}
render() {
console.log(this.state.data)
return (
<div>
<form onSubmit={this.handleForm}>
<input type="text" placeholder="Enter text" name="name" value={this.state.data.name} onChange={this.inputChange.bind(this, "name")} />
<select name="option" value={this.state.data.option} onChange={this.inputChange.bind(this, "option")}>
<option> Select Option </option>
<option value="1"> Option 1 </option>
<option vlaue="2"> Option 2 </option>
</select>
<button type="submit"> Submit </button>
</form>
</div>
);
}
}
ReactDOM.render(<Todo />, document.body)
<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>
Following the react tutorial:
class Example extends React.Component {
constructor() {
super();
this.state = {email:''};
this.handleEmailChange = this.handleEmailChange.bind(this);
}
handleEmailChange(event) {
this.setState({email: event.target.value});
}
render() {
return(
<div>
<input type="email" id="email" class="form-control" placeholder="Email"
value={this.state.email} onChange={this.handleEmailChange} />
</div>
);
}
}

Change select value in react.js

I need your help !
I'm on a project for my compagny and I should create a select field that can be duplicate with React. So, I have a little problem when I want to save my selection, if I refresh the page, the default option still the same (and not the selected one). There is my code for select.js:
import React, { Component, PropTypes } from 'react';
class Select extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
}
handleChange(data) {
this.setState({value:data.value});
}
render() {
return (
<label>
<select className="widefat" name={this.props.name} onChange={this.handleChange}>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
</label>
);
}
}
export default Select;
I change the default value :
When i change the select option
After a refresh
I think it's because in select.js It initialize the value to '' and don't save the selection but I don't know how to save the selection.
Here's a way to accomplish this:
import React, { Component, PropTypes } from 'react';
class Select extends Component {
constructor(props) {
super(props);
this.state = { value: props.value }; // can be initialized by <Select value='someValue' />
}
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
return (
<label>
<select className="widefat" value={this.state.value} name={this.props.name} onChange={this.handleChange.bind(this)}>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
</label>
);
}
}
export default Select;
Going further
You could iterate in a map in the render method to implement this like so:
render() {
const dictionary = [
{ value: 'grapefruit', label: 'Grapefruit' },
{ value: 'lime', label: 'Lime' },
{ value: 'coconut', label: 'Coconut' },
{ value: 'mango', label: 'Mango' }
];
return (
<label>
<select
className="widefat"
value={this.state.value}
name={this.props.name}
onChange={this.handleChange}
>
{dictionary.map(
// Iterating over every entry of the dictionary and converting each
// one of them into an `option` JSX element
({ value, label }) => <option key={value} value={value}>{label}</option>
)}
</select>
</label>
);
}
The target event property returns the element that triggered the event. It stores a lot of properties, print it to the console, that would familiarize with its capabilities
import React, { Component } from 'react';
class Select extends Component {
constructor(props) {
super(props);
this.state = { value: '' };
}
handleChange = e => this.setState({ value: e.target.value });
render() {
return (
<label>
<select className="widefat" name={this.props.name} onChange={this.handleChange}>
<option value="grapefruit">Grapefruit</option>
<option value="lime">Lime</option>
<option value="coconut">Coconut</option>
<option value="mango">Mango</option>
</select>
</label>
);
}
}
export default Select;
After a long journey to search in documentation and in the depth of internet I found my answer. I forgot to add a "for" for my label. There is my final code :
import React, { Component, PropTypes } from 'react';
class Select extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({value: this.props.value});
}
render() {
return (
<label htmlFor={this.props.id}>{this.props.label}
<select defaultValue={this.props.value} id={this.props.id} className="widefat" name={this.props.name} onChange={this.handleChange.bind(this)}>
<option>Aucun</option>
<option value="55">Option 2</option>
<option value="126">Backend configuration & installation</option>
<option value="125">Frontend integration</option>
<option value="124">Graphic Design</option>
</select>
</label>
);
}
}
export default Select;

Categories