Can't input data into form field React - reactjs

Hi I am making a form can someone please tell me why i cannot seem to enter text in the input fields. I did the type "text" and i thought that usually takes care of that. Any insight would be 100% appreciated.
import React, {Component} from 'react';
class CreateExercise extends Component{
constructor(){
super()
this.onChangeUsername = this.onChangeUsername.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
username:'',
description: '',
duration: 0,
users: []
}
}
componentDidMount() {
this.setState({
users: ['test user'],
username: 'test user'
})
}
onChangeUsername(e) {
this.setState({
username: e.target.value
});
}
onChangeUsername(e) {
this.setState({
description: e.target.value
});
}
onChangeUsername(e) {
this.setState({
duration: e.target.value
});
}
onSubmit(e) {
e.preventDefault();
const exercise = ({
username: this.state.username,
description: this.state.description,
duration: this.state.duration
})
console.log(exercise)
window.location = '/';
}
render(){
return(
<div>
<h3>Create New Exercise Log</h3>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Username: </label>
<select ref="userInput"
required
className="form-control"
value={this.state.username}
onChange={this.onChangeUsername}>
{
this.state.users.map(function(user) {
return <option
key={user}
value={user}>{user}
</option>
})
}
</select>
</div>
<div className="form-group">
<label>Description: </label>
<input type="text"
required
className="form-control"
value={this.state.description}
onChange={this.onChangeDescription}
/>
</div>
<div className="form-group">
<label>Duration (in minutes)</label>
<input
type="text"
className="form-control"
value={this.state.duration}
onChange={this.onChangeDuration}
/>
</div>
<div className="form-group">
<input type="submit" value="Create Exercise Log" className="btn btn-primary"/>
</div>
</form>
</div>
)
}
}
export default CreateExercise;

dont use {this.state} in your value fields. Theres no need for it.
also you have 3
onChangeUsername(e) {
im guessing you might want to update the other two methods

It seems like you have some missing handlers and bindings. For example, if you add the event handler onChangeDuration:
onChangeDuration(e) {
this.setState({
duration: e.target.value
});
}
and also do the binding inside the constructor method like:
this.onChangeDuration = this.onChangeDuration.bind(this);
Your duration field should be working.
You can apply the same logic to the description field as well.
Also do not forget to remove the unnecessary onChangeUsername methods. Hope that helps.

Related

how to set state from on change for multiple events react

in my react form I need to save each data item into the state.
I currently have on change methods for each of the inputs but its a lot of very similar code and looks messy. (But it does work...)
Here is the code
class EnterMortgage extends React.Component {
constructor(props) {
super(props);
this.state = {
repaymentType: '',
propVal: '',
bal: '',
fullTerm: '',
remainTerm: '',
intRate: '',
};
this.handleRepaymentChange = this.handleRepaymentChange.bind(this);
this.handlePropValChange = this.handlePropValChange.bind(this);
this.handleBalChange = this.handleBalChange.bind(this);
this.handleFullTermChange = this.handleFullTermChange.bind(this);
this.handleRemainTermChange = this.handleRemainTermChange.bind(this);
this.handleIntRateChange = this.handleIntRateChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleRepaymentChange(event) {
this.setState({ repaymentType: event.target.value });
}
handlePropValChange(event) {
this.setState({ propVal: event.target.value });
}
handleBalChange(event) {
this.setState({ bal: event.target.value });
}
handleFullTermChange(event) {
this.setState({ fullTerm: event.target.value });
}
handleRemainTermChange(event) {
this.setState({ remainTerm: event.target.value });=
}
handleIntRateChange(event) {
this.setState({ intRate: event.target.value });
}
handleSubmit(event) {
this.props.history.push('/EnterSavings', this.state);
}
// renders to display on page
render() {
return (
<div>
<div >
<p> Enter your mortgage details </p>
</div>
<div>
<form onSubmit={this.handleSubmit}>
<label>
Property Value {'\u00A3'}
<input type="Number" name="propVal" onChange={this.handlePropValChange} />
</label>
<label>
Current Balance
<input type="Number" name="bal" onChange={this.handleBalChange}/>
</label>
<label>
Full Mortgage Term (months)
<input type="Number" name="fullTerm" onChange={this.handleFullTermChange} />
</label>
<label>
Remaining Mortgage Term (months)
<input type="Number" name="remainTerm" onChange={this.handleRemainTermChange} />
</label>
<label>
InterestRate
<input type="Number" name="intRate" onChange={this.handleIntRateChange} />
</label>
<label>
Repayment Method
<select onChange={this.handleRepaymentChange}>
<option value="repayment">Repayment</option>
<option value="interest">Interest Only</option>
<option value="pap">Part and Part</option>
</select>
</label>
<input type="submit" value="Submit" />
</form>
</div>
</div>
);
}
}
export default EnterMortgage;
Is there a way to refactor this rather than having multiple functions? I have tried to combined into one method but I couldn't manage to get each item updated.

Updating/editing username in dropdown list in react

Can anyone help me.I have been trying to learn react for while now. How do I edit/update username in react dropdown list. Lets say there is a misspelled username in the dropdown list. If I want to change or edit that username how can I do that in react. I can update everything else, except the username. Here is my code..
import React, {Component} from 'react';
import axios from 'axios';
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css'
class EditExercise extends Component {
constructor(props){
super(props);
this.onChangeUsername = this.onChangeUsername.bind(this);
this.onChangeDescription = this.onChangeDescription.bind(this);
this.onChangeDuration = this.onChangeDuration.bind(this);
this.onChangeDate = this.onChangeDate.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.select = React.createRef();
this.state = {
username:'',
description : '',
duration: 0,
date:new Date(),
users: []
}
}
componentDidMount(){
axios.get('http://localhost:5000/exercises/'+this.props.match.params.id)
.then(responce => {
this.setState({
username: responce.data.username,
description: responce.data.description,
duration:responce.data.duration,
date: new Date(responce.data.date)
})
})
.catch((error) =>{
console.log(error)
})
axios.get('http://localhost:5000/exercises/')
.then(responce => {
if(responce.data.length > 0){
this.setState({
users: responce.data.map(user =>user.username),
});
}
})
}
onChangeUsername(e){
this.setState({
username: e.target.value
});
}
onChangeDescription(e){
this.setState({
description: e.target.value
});
}
onChangeDuration(e){
this.setState({
duration: e.target.value
});
}
onChangeDate(date){
this.setState({
date: date
})
}
onSubmit(e){
e.preventDefault();
const exercise = {
username : this.state.username,
description: this.state.description,
duration: this.state.duration,
date: this.state.date
}
console.log(exercise);
axios.post('http://localhost:5000/exercises/update/'+this.props.match.params.id, exercise)
.then(res => console.log(res.data));
window.location ='/';
}
render() {
return (
<div>
<h3>Edit Exercise Log</h3>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Username: </label>
<select ref={this.select}
required
className="form-control"
value={this.state.username}
onChange={this.onChangeUsername}>
{
this.state.users.map((user) => {
return <option
key={user}
value={user}>{user}
</option>
})
}
</select>
</div>
<div className="form-group">
<label>Description: </label>
<input type="text"
required
className="form-control"
value={this.state.description}
onChange={this.onChangeDescription}
/>
</div>
<div className="form-group">
<label>Duration (in minutes): </label>
<input type="text"
className="form-control"
value={this.state.duration}
onChange={this.onChangeDuration}
/>
</div>
<div className="form-group">
<label>Date: </label>
<div>
<DatePicker
selected={this.state.date}
onChange={this.onChangeDate}
/>
</div>
</div>
<div className="form-group">
<input type="submit" value="Edit Exercise Log" className="btn btn-primary" />
</div>
</form>
</div>
);
}
}
export default EditExercise;
First, I see that you have a dropdown list of users that is coming from an API call. I am not entirely sure what you mean by edit the name. If the names are coming from an API and you want a user to select from a list of usernames you would need to add another JSX Input component with type text just like you do with your other fields.
My suggestion would be to add an edit icon next to the dropdown menu that onClick will setState={editUsername: true, editableUserName: this.state.username}.
This will trigger a ternary operator that renders your new component to the page (see below) below the current username Dropdown menu:
Example:
{ this.state.editUsername ?
<div className="form-group">
<label>Edit Username: </label>
<input type="text"
required
className="form-control"
value={this.state.editableUserName}
onChange={this.onUpdateUsername}
/>
<button onClick="updateUsernameInDB()">
Save Username
</button>
</div>
: null
}
onUpdateUsername will need to update another state variable called editableUserName. Then when the user clicks save call the API that can edit the username of the user. One issue here is you will need some unique identifier for your username that you are updating or you can take the easier approach by sending the original username and the new username and update it that way although that is not the most sustainable over time. Then, when the API to update the username returns 200 you should setState={editUsername: false, updatedUsername: ''}
I hope this helps.

axios put request in react is returning empty

I'm pretty new with React and Call requests. I'm building a full stack app using React, express, MySql, and Sequelize.
Everything works fine except for the Put request to edit the client information. I'm using Axios to make those calls and I can add, see, and delete data from the app but the edit part is not working.
When hitting the submit button on the form, the Put request is returning an empty array instead of the actual modified data. My routes are Ok (I believe), as testing it with Postman work just fine. I'm almost sure that my problem is on the method being used in the axios call, but I can't just find the right way to make it work. Any help would be highly appreciated.
import React, { Component } from 'react';
import axios from 'axios';
import API from '../../utils/API';
class index extends Component {
constructor(props) {
super(props);
this.onChangeLastName = this.onChangeLastName.bind(this);
this.onChangeFirstName = this.onChangeFirstName.bind(this);
this.onChangePhone = this.onChangePhone.bind(this);
this.onChangePetName = this.onChangePetName.bind(this);
this.onChangeBreed = this.onChangeBreed.bind(this);
this.onChangeNotes = this.onChangeNotes.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
client: null
}
}
componentDidMount() {
let id = this.props.match.params.id
API.getClient(id)
.then(res => {
this.setState({
client: res.data
})
console.log(this.state.client.id)
})
.catch(error => console.log(error))
}
onChangeLastName(e) {
this.setState({
lastName: e.target.value
});
}
onChangeFirstName(e) {
this.setState({
firstName: e.target.value
});
}
onChangePhone(e) {
this.setState({
phone: e.target.value
});
}
onChangePetName(e) {
this.setState({
petName: e.target.value
});
}
onChangeBreed(e) {
this.setState({
breed: e.target.value
});
}
onChangeNotes(e) {
this.setState({
notes: e.target.value
});
}
onSubmit(e) {
e.preventDefault();
let obj = {
lastName: this.state.client.lastName.value,
firstName: this.state.client.firstName.value,
phone: this.state.client.phone.value,
petName: this.state.client.petName.value,
breed: this.state.client.breed.value,
notes: this.state.client.notes.value
};
let id = this.state.client.id
axios.put("http://localhost:3000/api/clients/" + id, obj)
// .then(alert("client Updated"))
.then(res => console.log(res))
.catch(error => console.log(error))
this.props.history.push('/admin');
}
render() {
const client = this.state.client ? (
<div className="client">
<h3 style={{ marginLeft: "60px" }}>Update Client</h3>
<form onSubmit={this.onSubmit} style={{ padding: "60px" }}>
<div className="form-group">
<label>Last Name: </label>
<input type="text"
className="form-control"
defaultValue={this.state.client.lastName}
onChange={this.onChangeLastName}
/>
</div>
<div className="form-group">
<label>First Name: </label>
<input type="text"
className="form-control"
defaultValue={this.state.client.firstName}
onChange={this.onChangeFirstName}
/>
</div>
<div className="form-group">
<label>Phone: </label>
<input type="text"
className="form-control"
defaultValue={this.state.client.phone}
onChange={this.onChangePhone}
/>
</div>
<div className="form-group">
<label>Pet Name: </label>
<input type="text"
className="form-control"
defaultValue={this.state.client.petName}
onChange={this.onChangePetName}
/>
</div>
<div className="form-group">
<label>Breed: </label>
<input type="text"
className="form-control"
defaultValue={this.state.client.breed}
onChange={this.onChangeBreed}
/>
</div>
<div className="form-group">
<label>Notes: </label>
<input type="text"
className="form-control"
defaultValue={this.state.client.notes}
onChange={this.onChangeNotes}
/>
</div>
<br />
<div className="form-group">
<input type="submit" value="Update Client"
className="btn btn-primary" />
</div>
</form>
</div>
) : (
<div className="center">Loading Client</div>
)
return (
<div className="container">
{client}
</div>
)
}
}
export default index;
I am assuming it is because of the way you are handling the onchange of your inputs. You want to set the onchange to the client value in your state. But instead you are setting it to the state itself. So then when you are building your object to send to the backend you are sending null data because you haven't set any data to the actual client value in your state and it is still null. Try console logging the state and you will see what I'm talking about. Also you are adding a .value to the end each of the state values you are trying to build your object with and this is not necessary. Finally you don't need to specify an onchange for each input just give the input a name attribute and you can set your onchange handler like so:
onChange = e => {
this.setState({
[e.target.name]: e.target.value
})
}
so your component would look something like the following:
import React, { Component } from 'react';
import axios from 'axios';
import API from '../../utils/API';
class index extends Component {
constructor(props) {
super(props);
this.onChange = this.onChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
client: null
}
}
componentDidMount() {
let id = this.props.match.params.id
API.getClient(id)
.then(res => {
this.setState({
client: res.data
})
console.log(this.state.client.id)
})
.catch(error => console.log(error))
}
onChange(e) {
this.setState({
client: {
...this.state.client,
[e.target.name]: e.target.value
}
});
}
onSubmit(e) {
e.preventDefault();
let obj = {
lastName: this.state.client.lastName,
firstName: this.state.client.firstName,
phone: this.state.client.phone,
petName: this.state.client.petName,
breed: this.state.client.breed,
notes: this.state.client.notes
};
let id = this.state.client.id
axios.put("http://localhost:3000/api/clients/" + id, obj)
// .then(alert("client Updated"))
.then(res => console.log(res))
.catch(error => console.log(error))
this.props.history.push('/admin');
}
render() {
const client = this.state.client ? (
<div className="client">
<h3 style={{ marginLeft: "60px" }}>Update Client</h3>
<form onSubmit={this.onSubmit} style={{ padding: "60px" }}>
<div className="form-group">
<label>Last Name: </label>
<input type="text"
name="lastName"
className="form-control"
defaultValue={this.state.client.lastName}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label>First Name: </label>
<input type="text"
name="firstName"
className="form-control"
defaultValue={this.state.client.firstName}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label>Phone: </label>
<input type="text"
name="phone"
className="form-control"
defaultValue={this.state.client.phone}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label>Pet Name: </label>
<input type="text"
name="petName"
className="form-control"
defaultValue={this.state.client.petName}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label>Breed: </label>
<input type="text"
name="breed"
className="form-control"
defaultValue={this.state.client.breed}
onChange={this.onChange}
/>
</div>
<div className="form-group">
<label>Notes: </label>
<input type="text"
name="notes"
className="form-control"
defaultValue={this.state.client.notes}
onChange={this.onChange}
/>
</div>
<br />
<div className="form-group">
<input type="submit" value="Update Client"
className="btn btn-primary" />
</div>
</form>
</div>
) : (
<div className="center">Loading Client</div>
)
return (
<div className="container">
{client}
</div>
)
}
}
export default index;
It could be because you're calling this.props.history.push immediately after calling axios.post, essentially redirecting before the POST request has a chance to return a response.
Try putting this.props.history.push('/admin') inside the .then().
You are doing multiple thing wrong here,
For every input you should have only 1 onChange handler, every input have name attribute to work with state. For example,
<input type="text"
className="form-control"
defaultValue={this.state.client.lastName}
name="lastName" //Like this should add name for every input like below
onChange={this.onChangeHandler} //This is a common onChangeHandler for every input should add in every input like below
/>
<input type="text"
className="form-control"
defaultValue={this.state.client.firstName}
name="firstName"
onChange={this.onChangeHandler}
/>
And onChangeHandler function should be,
onChangeHandler(e){
this.setState({
...this.state.client,
[e.target.name]:e.target.value
})
}
And finally your onSubmit function should be,
onSubmit(e) {
e.preventDefault();
let obj = {
lastName: this.state.client.lastName, //Remove `.value` as we are getting values from state and not directly from input
firstName: this.state.client.firstName,
phone: this.state.client.phone,
petName: this.state.client.petName,
breed: this.state.client.breed,
notes: this.state.client.notes
};
let id = this.state.client.id
axios.put("http://localhost:3000/api/clients/" + id, obj)
// .then(alert("client Updated"))
.then(res => console.log(res))
.catch(error => console.log(error))
this.props.history.push('/admin');
}
Note: You won't get value here in console.log,
API.getClient(id)
.then(res => {
this.setState({
client: res.data
})
console.log(this.state.client.id)
})
beacuse seState is async, you should use callback in setState to make console.log,
API.getClient(id)
.then(res => {
this.setState({
client: res.data
}, () => console.log(this.state.client.id)) //This is callback
})

State array updating on next click

I have 3 state values: username, password and address, and corresponding 3 textboxes where I am including the values in the respective states. Now I want that on click of a submit button, these states should be added on a state array called add_data:
state:
this.state = {
uname: '',
pass: '',
address:'',
salary:'',
add_data:[]
}
inputs:
<div>
<label>username:</label>
<input type="text" noValidate name="uname" onChange={this.changeHandler} />
</div>
<div>
<label>password:</label>
<input type="password" noValidate name="pass" onChange={this.changeHandler} />
</div>
<div>
<label>address:</label>
<textarea noValidate name="address" onChange={this.changeHandler}></textarea>
</div>
<div>
<button onClick={this.submitForm}>Edit</button>
</div>
click and change functions:
changeHandler = e => {
var adddata_obj;
this.setState({ [e.target.name]: e.target.value })
}
submitForm = () => {
console.log(this.state);
this.setState({
add_data: [...this.state.add_data, { username: this.state.uname, password: this.state.pass, address: this.state.address }]
})
}
The problem is that when I click on edit button, the add_data array does not update. Instead, when I change something else on the textboxes, it shows the value od edt_data fro the last click. Please help.
Here is a complete working code example (test it here: https://codesandbox.io/embed/mq66o03r3j):
import React from "react";
import {render} from "react-dom";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
uname: "",
pass: "",
address: "",
salary: "",
add_data: []
};
}
changeHandler = e => {
this.setState({[e.target.name]: e.target.value});
};
submitForm = () => {
this.setState({
add_data: [
...this.state.add_data,
{
username: this.state.uname,
password: this.state.pass,
address: this.state.address
}
],
uname: "",
pass: "",
address: "",
salary: ""
});
};
render() {
return (
<div>
<div>
<label>username:</label>
<input
type="text"
name="uname"
onChange={this.changeHandler}
value={this.state.uname}
/>
</div>
<div>
<label>password:</label>
<input
type="password"
name="pass"
onChange={this.changeHandler}
value={this.state.pass}
/>
</div>
<div>
<label>address:</label>
<textarea
name="address"
onChange={this.changeHandler}
value={this.state.address}
/>
</div>
<div>
<button onClick={this.submitForm}>Edit</button>
</div>
<div>
<p>Saved data:</p>
<table>
<tr>
<td>User</td>
<td>Password</td>
<td>Address</td>
</tr>
{this.state.add_data.map(d => (
<tr>
<td>{d.username}</td>
<td>{d.password}</td>
<td>{d.address}</td>
</tr>
))}
</table>
</div>
</div>
);
}
}
const rootElement = document.getElementById("root");
render(<App />, rootElement);
Now you can find your mistakes by yourself. Don't hesitate to ask me, when something is unclear.
Your code works fine #user3450590, see your snippet here just with the add_data being rendered out as a list https://stackblitz.com/edit/state-array-updating-on-next-click.
The only thing I changed was where you log the state. setSet is asynchronous ( see here), you can pass it a callback as a second argument if you need to log out the changes.
As per #virtusmaior's example you also leave the original values in the state which you may want to change when you submit your form.
Also as a nice little cherry on top your submit function would benefit from destructuring. ie
submitForm = () => {
console.log(this.state);
this.setState(state => {
const { add_data, ...values } = state;
return {
add_data: [...add_data, { ...values }]
};
});
}

React - Login Error from PHP not displaying

I am trying to display an error text message fetched from a PHP. I see from debugging that the message is returned correctly in the responseJson.message object but I'm not able to find out whether the state is updating it or why it is not rendering properly in the HTML since the page reloads itself and the input fields are emptied right after the this.setState({ error: responseJson.message }) instruction.
import React, { Component } from "react";
import { PostData } from '../../modules/PostData';
class LoginForm extends Component {
constructor() {
super()
this.state = {
error: "",
username: "",
password: ""
}
this.onSubmit = this.onSubmit.bind(this)
this.onChange = this.onChange.bind(this)
}
onSubmit() {
this.setState({ error: "" })
PostData('login', this.state).then((responseJson) => {
if (responseJson.message === "login success") {
sessionStorage.setItem('userData', JSON.stringify(responseJson));
document.location.href = `/home`
} else {
console.log(this.state.error)
this.setState({ error: responseJson.message })
}
})
}
onChange(e) {
this.setState({ [e.target.name]: e.target.value })
}
render() {
return (
<form onSubmit={this.onSubmit}>
<div>
<label htmlFor="username">Username:</label><br />
<input name="username" component="input" type="text" onChange={this.onChange}/>
</div>
<div>
<label htmlFor="password">Password:</label><br />
<input name="password" component="input" type="password" onChange={this.onChange}/>
</div>
<div>
<button type="submit">Login</button>
</div>
<div name="error" className='error' component="input" type="text" value={this.state.error}></div>
</form>
)
}
}
export default LoginForm
Thanks for the help!
There is no component, value, type attributes in div tag. In your case you should use:
<div name="error" className='error'>{this.state.error}</div>
or
<input name="error" className='error' component="input" type="text" value={this.state.error}></input>

Resources