If I have a dropdown with some options, I am able to display it properly and select and correct value getting displayed but for my use case, I wanted a modified value to be shown. Code taken below from react official documentation -
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) {
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 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>
);
}
}
In the dropdown when I select Mango, I just want to show the first 4 letters that are selected in dropdown, in this case Mang. How to do that?
you can use substring method on your string and shorten it
alert('Your favorite flavor is: ' + this.state.value.substring(0,4);
Related
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
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.
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>
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;
I have a form:
<form onSubmit={this.onSubmit}>
<input ref="name" type="text" />
...
<select ref="pet">
<option>Dog</option>
<option>Cat</option>
</select>
</form>
In another place, I have a different form, with different inputs, but the same select. I could simply bindly copy the code from the first one, but I don't want to.
I want to make a component. In terms of UI, I know it would work. However, I have no idea how to access this.refs.pet.value in that case:
<form onSubmit={this.onSubmit}>
<input ref="name" type="text" />
...
<PetsSelect ??????? />
</form>
How to access the value of the select box from the component, in its parent (form)?
very quick example on composing
class PetsSelect extends React.Component {
get value(){
return this.state.value
}
handleChange(key, value){
this.setState({[key]: value})
this.props.onChange && this.props.onChange(key, value)
}
constructor(props){
super(props)
this.state = { value: props.value || '', name: '' }
}
render(){
// add the name etc and then you can handleChange('name', ...)
// or make it more DRY
return <div>
<select
ref={select => this.select = select}
value={this.state.value}
onChange={e => this.handleChange('value', e.target.value)}>
<option value=''>Please select</option>
<option value='dog'>Dog</option>
<option value='cat'>Cat</option>
</select>
</div>
}
}
class Form extends React.Component {
handleSubmit(e){
e.preventDefault()
console.log(this.pets.value)
}
render(){
// this.pets becomes the instance of the PetsSelect class.
return <form onSubmit={e => this.handleSubmit(e)}>
<PetsSelect ref={pets => this.pets = pets} />
<button type='submit'>try it</button>
</form>
}
}
ReactDOM.render(<Form />, document.getElementById('app'))
see here: https://codepen.io/anon/pen/WExepp?editors=1010#0. basically, you can either: onChange and get the value in the parent, or read the value of the child when needed.
keep in mind you said 'controlled' - i am not doing anything to keep props.value with state.value - and in uncontrolled, you'd use defaultValue
Just add ref like this <PetsSelect ref="petSelect"/> and get value by this this.refs.petSelect.refs.pet.value .
class FormComponent extends React.Component{
constructor(props){
super(props)
this.state = {selected: null,
...
}
}
selectPet(e){
this.setState({selected: e.target.value})
}
render(){
return (<form onSubmit={this.onSubmit}>
<input ref="name" type="text" />
...
<PetsSelect onSelect={this.selectPet.bind(this)} />
</form>)
}
}
class PetsSelect extends React.Component{
constructor(props){
super(props)
}
render(){
return (<select onChange={this.props.onSelect}>
<option value='dog'>Dog</option>
<option value='cat'>Cat</option>
</select>)
}
}