onChange in select not working in react js - reactjs

this is my code, the value of this.state.year is not changing when onChange event is triggered in select. I don't know why. can any one help me out
import React, { Component } from 'react'
import './ReportGen.css'
export class ReportGen extends Component {
constructor() {
super();
this.state = {
year: 'Academic Year'
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({year: event.target.value});
}
handleSubmit(event) {
console.log(this.state);
event.preventDefault();
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<select className='drop-down' placeholder='academic year' name='0' onChange={(e) => this.handleChange}>
<option value="Academic Year" >Academic Year</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
<input type="submit" value="Submit" />
</form>
</div>
)
}
}
export default ReportGen
when im changing the option and click submit, im still getting academic year as output in the console

You're not actually calling the function:
(e) => this.handleChange
When you do something like this:
onSubmit={this.handleSubmit}
You don't call the function, but pass the function to the onSubmit handler so it will be called when that event happens.
But when you do this:
onChange={(e) => this.handleChange}
You create your own function wrapped around the function you want to call. The function you created is passed to the onChange handler so it will be called when that event happens. But what does *your function do? It becomes more clear if we change the syntax a bit:
onChange={function (e) {
this.handleChange;
}}
As you can see, your function does nothing. It just has a single reference to this.handleChange but never invokes it. You can invoke it:
onChange={(e) => this.handleChange(e)}
Or, even simpler, so what you're already doing in the onSubmit handler and just pass the function reference directly:
onChange={this.handleChange}

You should pass the e parameter to your function: onChange={(e) => this.handleChange(e)}

Related

Two dropdowns in a React Form

I want to get the users input of a form with two drop-downs, and store it inside a global variable using react. I looked at reacts docs on how to create forms, and manipulate their code a little bit to have two drop-downs, but can't get it to save the variable as a global variable and print that global variable onto the screen. Unfortunately, there was an error when I clicked the second submit button (The first button did nothing). Here was the error: TypeError: this is undefined handleSubmit src/App.js:55 52 | } 53 | handleSubmit(event) { 54 | event.preventDefault(); > 55 | two = this.state.value | ^ 56 | } 57 | 58 | render() { – . Here was my code inside App.js:
import React from "react";
import "./App.css";
var one = "";
var two = "";
class FlavorFormOne 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) {
event.preventDefault();
one = this.state.value
}
render() {
return (
<div>
<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>
</div>
);
}
}
class FlavorFormTwo extends React.Component {
constructor(props) {
super(props);
this.state = { value: "GrabeFruit" };
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({ value: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
two = this.state.value
}
render() {
return (
<div>
<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>
</div>
);
}
}
function App() {
return (
<>
<FlavorFormOne />
<FlavorFormTwo />
{one}
{two}
</>
);
}
export default App;
you didn't pass the event
try onSubmit={(e)=>this.handleSubmit(e)}
also onChange={(e)=>this.handleChange(e)}
There were a couple things that needed to be fixed in your code. The first was this.handleSubmit = this.handleSubmit.bind(this); needed to be added in FlavorFormTwo's constructor, as I mentioned in the comments. The second was your handling of global variables. React won't re-render a component when a global variable changes, but it will re-render when the state is changed with setState. This is the reason why react state doesn't update when using this.state =. Instead, I added onSubmit as a prop to both, and inside both handleSubmit functions I added this.props.onSubmit(this.state.value). I changed the App component to a class, and added functions for handleOneSubmit and handleTwoSubmit that set the state of app. Try it online: https://codesandbox.io/s/vibrant-smoke-tsgri?file=/src/App.js
import React from "react";
import "./App.css";
class FlavorFormOne 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) {
event.preventDefault();
this.props.onSubmit(this.state.value);
}
render() {
return (
<div>
<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>
</div>
);
}
}
class FlavorFormTwo extends React.Component {
constructor(props) {
super(props);
this.state = { value: "GrabeFruit" };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ value: event.target.value });
}
handleSubmit(event) {
event.preventDefault();
this.props.onSubmit(this.state.value);
}
render() {
return (
<div>
<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>
</div>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = { one: "", two: "" };
this.handleOneSubmit = this.handleOneSubmit.bind(this);
this.handleTwoSubmit = this.handleTwoSubmit.bind(this);
}
handleOneSubmit(value) {
this.setState({ one: value });
}
handleTwoSubmit(value) {
this.setState({ two: value });
}
render() {
return (
<>
<FlavorFormOne onSubmit={this.handleOneSubmit} />
<FlavorFormTwo onSubmit={this.handleTwoSubmit} />
{this.state.one}
{this.state.two}
</>
);
}
}
export default App;

TypeError: Cannot read property 'value' of undefined React, Ant select

I cannot get React Ant Form Select value as it is undefined. I have tried updating state and anything but nothing solves this issue. Error is located under handleChange method. Maybe i am handling wrong Ant design form.
What could be issue here?
My form code:
import React from "react";
import { Form, Input, Button, Select } from "antd";
import axios from "axios";
const FormItem = Form.Item;
const { Option } = Select;
class CustomForm extends React.Component {
constructor(props) {
super(props)
this.state = {sport: ''};
this.handleChange = this.handleChange.bind(this);
this.handleFormSubmit = this.handleFormSubmit.bind(this);
}
handleChange(event) {
const target = event.target;
const value = target.value;
const name = target.name;
this.setState({
[name]: value
});
}
handleFormSubmit = (event, requestType, trainingID) => {
const sport = event.targets.elements.sport.value;
...
}
render() {
return (
<div>
<Select name="sport" value={this.state.sport} style={{ width: 120 }} onChange={this.handleChange}>
<Option value="jooks" >Jooks</Option>
<Option value="jõud" >Jõud</Option>
<Option value="crossfit" >Crossfit</Option>
<Option value="kardio" >Kardio</Option>
</Select>
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" shape="round" >
{this.props.btnText}
</Button>
</FormItem>
</Form>
</div>
);
}
}
The onChange event for the antd select component does not provide an event object, it provides the actual value that has been selected.
Instead, change your handleChange method to
handleChange(name, value) {
this.setState({
[name]: value
});
}
and then change your select onChange function to
onChange={value => this.handleChange("sport", value)}
So it would like like this
<Select
name="sport"
value={this.state.sport}
style={{ width: 120 }}
onChange={value => this.handleChange("sport", value)}
>
<Option value="jooks">Jooks</Option>
<Option value="jõud">Jõud</Option>
<Option value="crossfit">Crossfit</Option>
<Option value="kardio">Kardio</Option>
</Select>
The easiest way to actually debug this situation would be to console log the event value passed in from the onChange event. This would have shown that it is in fact the value that was selected, and not an event object.
EDIT:
Im not sure if it was by accident, but <Form> and <FormItem> tags were missing. I have added the full class below
import React from "react";
import { Form, Input, Button, Select } from "antd";
import axios from "axios";
const FormItem = Form.Item;
const { Option } = Select;
export default class CustomForm extends React.Component {
constructor(props) {
super(props);
this.state = { sport: "" };
this.handleChange = this.handleChange.bind(this);
this.handleFormSubmit = this.handleFormSubmit.bind(this);
}
handleChange(name, value) {
this.setState({
[name]: value
});
}
handleFormSubmit = value => {
console.log(this.state);
};
render() {
return (
<div>
<Form onFinish={this.handleFormSubmit}>
<FormItem>
<Select
name="sport"
value={this.state.sport}
style={{ width: 120 }}
onChange={value => this.handleChange("sport", value)}
>
<Option value="jooks">Jooks</Option>
<Option value="jõud">Jõud</Option>
<Option value="crossfit">Crossfit</Option>
<Option value="kardio">Kardio</Option>
</Select>
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit" shape="round">
{this.props.btnText}
</Button>
</FormItem>
</Form>
</div>
);
}
}

Adding an arrow function to input field results an error

Here is a React class I'm working on:
import React from 'react';
export default class ExpenseForm extends React.Component {
state = {
title: ''
};
onTitleChange = (e) => {
const title = e.target.value;
this.setState(() => ({title}));
};
render() {
return (
<div>
<form>
<input
type='text'
placeholder='title'
value={this.state.title}
onChange={(e) => this.setState(() => ({title: e.target.value}))}
required autoFocus/>
<textarea placeholder='Add a note for your expense'/>
<input type='number' placeholder='amount' required/>
<input type='submit' value='Add Expense'/>
</form>
</div>
);
}
}
This throws an error Uncaught TypeError: Cannot read property 'value' of null when executing onChange.
But when I restructure inner js of onChange into a separate function onTitleChange and calling that function: onChange={this.onTitleChange}, it works perfectly. What could be the reason behind this behavior?
Here you assigned onchange event as onChange={(e) => this.setState(() => ({title: e.target.value}))}, here e.target.value will not work, because its inside the setState() scope.
On expanding your function, we will get
function(e){
this.setState(function(){
return {
title: e.target.value
}
})
}
Here there is no e in function inside setSate(), so e.target.value will be error;
Since you dont want to compare with previous value and only need to set the value to title, you can use like
onChange={(e) => this.setState({title: e.target.value})}
There is no need for an extra function inside setState
I would guess, that your parameter e is not known in the inner arrow function.
You could write it like this:
<input
type='text'
placeholder='title'
value={this.state.title}
onChange={e => this.setState({ title: e.target.value })}
required
autoFocus
/>
That is because of React is utilizing event pooling and setState is a function executed in asynchronous context, so you observe them as nulls in the asynchronous setState callback.
You need to either persist event using e.persist() or save the value of event to variable, as in your method.
You don't need to use arrow function inside setstate.
change
onChange={(e) => this.setState(() => ({title: e.target.value}))}
to:
onChange={(e) => this.setState({title: e.target.value})}

Use onSubmit to setState for the multiple inputs?

I want to take the data from these two inputs within my form and set one as state.name, and the other as state.option. Is there a way to set them upon using the form submit button rather than using individual onChange handlers to set each of those states? If not, it feels awkward having a submit button that doesn't really do anything.
onTextChange(name) {
this.setState({ name });
console.log(this.state.name);
}
onOptionChange(option) {
this.setState({ realm });
console.log(this.state.option);
}
onSubmitForm(event) {
event.preventDefault();
}
render() {
return (
<div>
<h3>Enter Name:</h3>
<form onSubmit={event => this.onSubmitForm(event.target.value)}>
<input
type="text"
placeholder="Name"
value={this.state.name}
onChange={event => this.onTextChange(event.target.value)}
/>
Select Option:
<select onChange = {event => this.onOptionChange(event.target.value)}>
<option value="1">Option 1</option>
<option value="2">Option 2</option>
</select>
<input type="submit" />
</form>
In React, you have to control what happens in form/input in state and setState to change it. That's call Single source of truth
Welcome to React :)

React Modifying Textarea Values

I am working on a project which is basically notepad. I am having problems though updating the <textarea>'s value when an ajax call is made. I tried setting the textarea's value property but then no changes to its value can be made. How can I make it so on a state change the textarea's value changes and can be edited.
The code I have is as follows.
In the parent class
<Editor name={this.state.fileData} />
In the Editor class
var Editor = React.createClass({
render: function() {
return (
<form id="noter-save-form" method="POST">
<textarea id="noter-text-area" name="textarea" value={this.props.name}></textarea>
<input type="submit" value="Save" />
</form>
);
}
});
I can't use defaultValue because the value of the textarea is not known on page load and when I try and put the data between the textareas nothing happens. I would like it to take the state value whenever the state changes but have it editable in between.
Thanks
Edit
I managed to get it working using jQuery but would like to do it in React instead, I called this before render:
$('#noter-text-area').val(this.props.name);
I think you want something along the line of:
Parent:
<Editor name={this.state.fileData} />
Editor:
var Editor = React.createClass({
displayName: 'Editor',
propTypes: {
name: React.PropTypes.string.isRequired
},
getInitialState: function() {
return {
value: this.props.name
};
},
handleChange: function(event) {
this.setState({value: event.target.value});
},
render: function() {
return (
<form id="noter-save-form" method="POST">
<textarea id="noter-text-area" name="textarea" value={this.state.value} onChange={this.handleChange} />
<input type="submit" value="Save" />
</form>
);
}
});
This is basically a direct copy of the example provided on https://facebook.github.io/react/docs/forms.html
Update for React 16.8:
import React, { useState } from 'react';
const Editor = (props) => {
const [value, setValue] = useState(props.name);
const handleChange = (event) => {
setValue(event.target.value);
};
return (
<form id="noter-save-form" method="POST">
<textarea id="noter-text-area" name="textarea" value={value} onChange={handleChange} />
<input type="submit" value="Save" />
</form>
);
}
Editor.propTypes = {
name: PropTypes.string.isRequired
};
As a newbie in React world, I came across a similar issues where I could not edit the textarea and struggled with binding. It's worth knowing about controlled and uncontrolled elements when it comes to react.
The value of the following uncontrolled textarea cannot be changed because of value
<textarea type="text" value="some value"
onChange={(event) => this.handleOnChange(event)}></textarea>
The value of the following uncontrolled textarea can be changed because of use of defaultValue or no value attribute
<textarea type="text" defaultValue="sample"
onChange={(event) => this.handleOnChange(event)}></textarea>
<textarea type="text"
onChange={(event) => this.handleOnChange(event)}></textarea>
The value of the following controlled textarea can be changed because of how
value is mapped to a state as well as the onChange event listener
<textarea value={this.state.textareaValue}
onChange={(event) => this.handleOnChange(event)}></textarea>
Here is my solution using different syntax. I prefer the auto-bind than manual binding however, if I were to not use {(event) => this.onXXXX(event)} then that would cause the content of textarea to be not editable OR the event.preventDefault() does not work as expected. Still a lot to learn I suppose.
class Editor extends React.Component {
constructor(props) {
super(props)
this.state = {
textareaValue: ''
}
}
handleOnChange(event) {
this.setState({
textareaValue: event.target.value
})
}
handleOnSubmit(event) {
event.preventDefault();
this.setState({
textareaValue: this.state.textareaValue + ' [Saved on ' + (new Date()).toLocaleString() + ']'
})
}
render() {
return <div>
<form onSubmit={(event) => this.handleOnSubmit(event)}>
<textarea rows={10} cols={30} value={this.state.textareaValue}
onChange={(event) => this.handleOnChange(event)}></textarea>
<br/>
<input type="submit" value="Save"/>
</form>
</div>
}
}
ReactDOM.render(<Editor />, document.getElementById("content"));
The versions of libraries are
"babel-cli": "6.24.1",
"babel-preset-react": "6.24.1"
"React & ReactDOM v15.5.4"

Resources