I'm trying for this component to show the specific form based upon the option select. I'm using the switch statement for conditional rendering. But at the moment it's not working, what am I missing?
class Form extends Component {
state = {
selectedValue: ''
};
handleChange(event) {
this.setState({selectedValue: event.target.value});
}
renderSelectedForm = (param) => {
const formStyle = {
display: 'none'
}
switch(param) {
case 'form_name1':
return <form name="form_name1" id="form_name1" style={formStyle}>
form 1
</form>;
case 'form_name2':
return <form name="form_name1" id="form_name2" style={formStyle}>
form 2
</form>;
case 'form_name3':
return <form name="form_name1" id="form_name3" style={formStyle}>
form 3
</form>;
default:
return null;
}
}
render() {
return (
<div>
<div className={styles.ContactUs}>
<form >
<select value={this.state.selectedValue} onChange={this.handleChange}>
<option value="form_name1">Form 1</option>
<option value="form_name2">Form 2</option>
<option value="form_name3">Form 3</option>
</select>
</form>
{this.renderSelectedForm(this.state.selectedValue)}
</div>
</div>
);
}
}
export default Form;
Your display is set to 'none'.
handleChange = (event) => {
this.setState({ selectedValue: event.target.value });
}
You either need to make a constructor that binds this for the handleChange function or just declare it in the way above, which auto-binds.
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
Set a default value in your state for the first form to be shown, such as form_name1. Or add an option like 'Select a form' to your select element.
If you're doing conditional rendering, you don't really need to set display: none in your elements. Each element will be rendered according to your current state and null is returned for unmounting the component.
class Form extends React.Component {
constructor(props) {
super(props)
this.state = {
selectedValue: 'form_name1'
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
this.setState({selectedValue: event.target.value});
}
renderSelectedForm (param) {
switch(param) {
case 'form_name1':
return (
<form name="form_name1" id="form_name1">
form 1
</form>
)
case 'form_name2':
return (
<form name="form_name1" id="form_name2">
form 2
</form>
)
case 'form_name3':
return (
<form name="form_name1" id="form_name3">
form 3
</form>
)
default: return null;
}
}
render() {
return (
<div>
<form>
<select value={this.state.selectedValue} onChange={this.handleChange}>
<option value="form_name1">Form 1</option>
<option value="form_name2">Form 2</option>
<option value="form_name3">Form 3</option>
</select>
</form>
{this.renderSelectedForm(this.state.selectedValue)}
</div>
);
}
}
Here's in action: https://codepen.io/herodrigues/pen/XOBLVb
You need to wrap inside (). Like below
switch(param) {
case 'form_name1':
return (<form name="form_name1" id="form_name1" style={formStyle}>
form 1
</form>);
...
}
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 am trying to create a simple drop down in react and I am facing two issues. The code that I have is:
import React from "react";
class EditEmployee extends React.Component {
constructor() {
super();
this.state={
salary:''
}
}
validateSalary=(e)=>{
// e.persist();
var val=e.target.value;
this.setState((prevState)=>{prevState.salary=val})
}
render() {
return (
<form>
<div className="form-group">
<label>Salary:</label>
<select onChange={this.validateSalary} className="form-control" value={this.state.salary}>
<option value="20000">20000</option>
<option value="30000">30000</option>
<option value="40000">40000</option>
<option value="50000">50000</option>
</select>
</div>
</form>
);
}
}
export default EditEmployee
Issue 1 - When I select an option, I am able to get the value in the console, but the drop down is not showing the selected value. I am setting the state properly and I am not sure why is it not updating the view.
Issue 2 - If I directly access the event inside setState I get an warning about synthetic event and the code does not work. Why do I need e.persist() to avoid it?
validateSalary(e){
// e.persist();
var val=e.target.value;
this.setState({
salary = val
});
}
<select onChange={e => this.validateSalary(e)} className="form-control" value={this.state.salary}>
<option value="20000">20000</option>
<option value="30000">30000</option>
<option value="40000">40000</option>
<option value="50000">50000</option>
</select>
OR
you need to change your function
validateSalary=(e)=> {
var val = e.target.value;
this.setState({
salary = val
});
}
Can you try this code. I think it is problem in some callback
Try with this change
validateSalary=(e)=> {
let val = e.target.value;
this.setState({salary:val})
}
This will solve your both the issues.
import React from "react";
class EditEmployee extends Component {
constructor(props) {
super(props);
this.state = {
salary: ""
};
}
validateSalary = e => {
// e.persist();
const { name, value } = e.target;
this.setState({ [name]: value }, function() {
console.log(this.state);
});
};
render() {
return (
<form>
<div className="form-group">
<label>Salary:</label>
<select
name="salary"
onChange={this.validateSalary}
className="form-control"
value={this.state.salary}
>
<option value="">Please select salary</option>
<option value="20000">20000</option>
<option value="30000">30000</option>
<option value="40000">40000</option>
<option value="50000">50000</option>
</select>
</div>
</form>
);
}
}
export default EditEmployee;
i'm consoling the state after state is updated, because if you console the state outside you will get previous state value.
How can I link to a value when selected onChange in a select box?
Looking to implement a select menu into ReactJS that links to the value onChange.
render() {
return (
<select onChange={() => {if (this.value) window.location.href=this.value}}>
<option value="">Please select</option>
{pages.map(({ node: page })=> (
<option key={page.id} value="{page.slug}">{page.title}</option>
))}
</select>
);
}
This is getting the value (I believe) but I keep getting the error of Cannot read property 'value' of undefined
I have tried following the documents here as suggested in some answers yet I have not been able to get this working with my current code - see as follows the full Page.js
import React from 'react'
import Helmet from 'react-helmet'
import styled from 'styled-components'
import config from '../utils/siteConfig'
const PageCompany = ({data}) => {
const {title,slug} = data.contentfulCompanyPage;
const pages = data.allContentfulCompanyPage.edges;
return(
<Wrapper>
<CompanyMenu>
<div>
<select onChange={() => {if (this.value) window.location.href=this.value}}>
<option value="">Please select</option>
{pages.map(({ node: page })=> (
<option key={page.id} value="{page.slug}">{page.title}</option>
))}
</select>
</div>
</CompanyMenu>
</Wrapper>
)
}
export const companyQuery = graphql`
query companyQuery($slug: String!) {
contentfulCompanyPage(slug: {eq: $slug}) {
title
slug
keywords
description
heroBg {
sizes(maxWidth: 1500) {
src
}
}
}
allContentfulCompanyPage(sort: {fields: [menuOrder], order: ASC}) {
edges {
node {
id
title
slug
}
}
}
}
`
export default PageCompany
Instead of making use of Global window.location property you can make a separate method handleChange like :
constructor(props) {
super(props);
this.state = { }; // initialise state
// Make sure to bind handleChange or you can make use of arrow function
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
const targetValue = e.target.value;
// Then you can do whatever you want to do with the value
this.setState({
[name]: targetValue
});
EDIT : In order to make use of constructor make sure you are defining components using class syntax like:
import React , { Component } from 'react';
class PageCompany extends Component {
constructor(props) {
super(props);
this.state = { }; // initialise state
this.handleChange = this.handleChange.bind(this);
}
// Make sure class has a render method
render () {
return ()
}
}
And inside your <Select> You can reference it to handleChange
<select onChange={this.handleChange}>
You can read more about onChange Here
You need to pass the event param and then grab the value from the target of that event e.g.
onChange={(event) => this.setState({value: event.target.value})}
There's a great example here.
Full code excerpt from linked docs:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
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>
);
}
}
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>)
}
}