I want to add an item to a react state dictionary. Every time i press to submit i got the value is undefined on the dictionary object and it is append to the dictonary with a null values in name and cost but id is working fine. I find the issue but i am unable to find the solution. TIA.
import React, { Component } from "react";
import ExpenseItem from "./ExpenseItem.js";
class ExpensesList extends Component {
state = {
expenses: [{id: '12345' ,name: 'Pizza', cost: '20'}],
};
handleChange=(event)=>{
this.setState({[event.target.name]:event.target.value});
}
handleSubmit = (event) => {
event.preventDefault();
this.setState({expenses: [this.state.expenses,...[{id: Math.random(),name:this.state.expenses.name, cost:this.state.expense.cost}]]});
}
render() {
return (
<div>
<ul className="list-group">
{this.state.expenses.map((expense) => (
<ExpenseItem
id={expense.id}
name={expense.name}
cost={expense.cost}
/>
))}
</ul>
<div className ="row mt-3">
<h2> Add Expenses </h2>
<form onSubmit={this.handleSubmit}>
<div className="row">
<div className="form-group">
<label for="name">Name</label>
<input
required="required"
type="text"
className="form-control"
id="name"
value = {this.state.expenses.name}
onChange = {this.handleChange}
></input>
</div>
<div className="form-group">
<label for="name">Cost</label>
<input
required="required"
type="text"
className="form-control"
id="cost"
value = {this.state.expenses.cost}
onChange = {this.handleChange}
></input>
</div>
<div className="form-group">
<button type="submit" className="btn btn-primary"> Add Expense</button>
</div>
</div>
</form>
</div>
</div>
);
}
}
export default ExpensesList;
The issues is that this.state.expenses is an array. So, this.state.expenses.name and this.state.expenses.cost are both undefined.
If you want to be able to add new expense objects to the expenses array in state, you need a way to manage the new inputs in state. So, your state should look something like this:
state = {
expenses: [{id: '12345' ,name: 'Pizza', cost: '20'}],
cost: "",
name: ""
};
When a user inputs a cost and name, this.state.cost and this.state.name should be set in state, and then when the user clicks 'submit', a new object can be added to the this.state.expenses array.
(Also, your handleChange needs to specify which properties of state it intends to udpate)
Your final solution should look something like this:
import React, { Component } from "react";
import ExpenseItem from "./ExpenseItem.js";
class ExpensesList extends Component {
state = {
expenses: [{ id: '12345', name: 'Pizza', cost: '20' }],
cost: "",
name: ""
};
handleChange = (event, name) => {
this.setState({ [name]: event.target.value });
};
handleSubmit = (event) => {
event.preventDefault();
let newExpense = {
id: Math.random(),
name: this.state.name,
cost: this.state.cost
}
this.setState(prevState => ({
expenses: [...prevState.expenses, newExpense], // add new expense to expenses array
cost: "", // reset this field
name: "" // reset this field
}));
}
render() {
return (
<div>
<ul className="list-group">
{this.state.expenses.map((expense) => (
<ExpenseItem
id={expense.id}
name={expense.name}
cost={expense.cost}
/>
))}
</ul>
<div className="row mt-3">
<h2> Add Expenses </h2>
<form onSubmit={this.handleSubmit}>
<div className="row">
<div className="form-group">
<label for="name">Name</label>
<input
required="required"
type="text"
className="form-control"
id="name"
value={this.state.name}
onChange={e => this.handleChange("name")}
></input>
</div>
<div className="form-group">
<label for="name">Cost</label>
<input
required="required"
type="text"
className="form-control"
id="cost"
value={this.state.cost}
onChange={e => this.handleChange("cost")}
></input>
</div>
<div className="form-group">
<button type="submit" className="btn btn-primary"> Add Expense</button>
</div>
</div>
</form>
</div>
</div>
);
}
}
export default ExpensesList;
Related
I want to get the selected value from the dropdown on button click and then I want to save it in the firebase database. Everything is working fine except dropdown. I also want to add a dropdown value in the firebase database. Anyone can help me how can I get it? I'm trying but it is giving error. Anyone can help me?
import React, { Component } from 'react';
import Select from 'react-select';
import firebase from '../config/firebase.js';
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' },
];
class PostAd extends React.Component {
constructor() {
super();
this.state = {
selectedOption: null,
ads: [],
};
}
handleClick = () => {
firebase.database().ref('/').child('ads').push(this.state);
console.log(`Option selected:`, selectedOption);
};
handleChange = (e) => {
this.setState({
selectedOption,
[e.target.name]: e.target.value,
});
console.log(`Option selected:`, selectedOption);
};
render() {
const { selectedOption } = this.state;
return (
<div className="container postAd-container">
<h6 className="p-3">CHOOSE A CATEGORY</h6>
<hr />
<Select value={selectedOption} onChange={this.handleChange} options={options} />
<div className="p-3">
<div className="">
<p>Condition *</p>
<button className="btn-attributes" name="new" value="new" onClick={this.handleChange}>
New
</button>
<button className="btn-attributes" name="used" value="used" onClick={this.handleChange}>
Used
</button>
</div>
<div className="pt-2">
<p>Type *</p>
<button className="btn-attributes">Apple</button>
<button className="btn-attributes">Dany Tabs</button>
<button className="btn-attributes">Q Tabs</button>
<button className="btn-attributes">Samsung</button>
<button className="btn-attributes">Other Tablets</button>
</div>
<div className="pt-5">
<p>Ad Title *</p>
<div className="form-group row">
<div className="col-sm-6">
<input
type="email"
name="adTitle"
onChange={this.handleChange}
className="form-control form-control-lg"
/>
<p className="font-11">Mention the key features of your item (e.g. brand, model, age, type) 0 / 70</p>
</div>
</div>
</div>
<div className="pt-5">
<p>Description *</p>
<div className="form-group row">
<div className="col-sm-6">
<textarea name="description" onChange={this.handleChange} className="form-control" rows="3"></textarea>
<p className="font-11">Include condition, features and reason for selling 0 / 4096</p>
</div>
</div>
</div>
</div>
<hr />
<div className="p-4">
<div className="">
<h6>SET A PRICE</h6>
<div className="form-group row">
<div className="col-sm-6">
<div className="input-group mb-2">
<div className="input-group-prepend">
<div className="input-group-text">Rs</div>
</div>
<input type="number" name="price" onChange={this.handleChange} className="form-control" />
</div>
</div>
</div>
</div>
</div>
<div className="form-row pb-3">
<div className="col-md-12 text-center">
<button type="submit" className="btn btn-primary" onClick={this.handleClick}>
Post Ad
</button>
</div>
</div>
</div>
);
}
}
export default PostAd;
Make a seperate function this.handleClickButton and use it for New and Used buttons. instead this.handleChange
handleClickButton = e => {
this.setState({
[e.target.name]: e.target.value
});
};
handleChange = selectedOption => {
this.setState({
selectedOption
},() => {
console.log(`Option selected:`, this.state.selectedOption);
});
};
This code will change the dropdown without any error.
If you would like to manage both with the same function. Following is the solution:
handleChange = selectedOption => {
//onClick it will get e.target.value
if (e.target.value) {
this.setState({
[e.target.name]: e.target.value
});
} else {
//onChange it will get the selected option.
this.setState({
selectedOption: e
});
}
};
friends, I am a React beginner, and I have a problem with passing data between components using props
I have three components Users, UserList, and AddUser. In the UserList component, all the users should be displayed and AddUser component contains a form. I want to grab data from the forms and update my state in Users component. My pages are Home, User List and Add New User
import React, { Component } from "react";
import UserList from "./userList";
class Users extends Component {
state = {
users: [
{
name: "ali",
lastname: "ahmadi",
language: "python",
gender: "male",
score: 100,
},
{
name: "Ahmad",
lastname: "moradi",
language: "JavaScript",
gender: "male",
score: 90,
},
],
};
removeUser = (name) => {
let users = this.state.users.filter((user) => {
return user.name !== name;
});
this.setState({
users,
});
};
render() {
return (
<div>
<UserList users={this.state.users} removeUser={this.removeUser} />
</div>
);
}
}
export default Users;
and my user list components code
import React from "react";
import Users from "./user";
const UserList = (props) => {
const { users } = props;
console.log(users);
return (
<div className="container">
<h1 className="text-center mt-4" style={{ fontFamily: "tahoma" }}>
All Users
</h1>
</div>
);
};
export default UserList;
here is my form component
import React, { Component } from "react";
import Users from "./user";
class AddUser extends Component {
state = {
name: "",
lastname: "",
language: "",
score: 0,
gender: "",
};
handleChange = (e) => {
this.setState({
[e.target.id]: e.target.value,
gender: e.target.value,
});
};
handleSubmit = (e) => {
e.preventDefault();
};
render() {
return (
<div className="container">
<form onSubmit={this.handleSubmit} className="col-lg-8 m-auto">
<fieldset className="form-group">
<legend>Add New User</legend>
<div className="form-group ">
<input
type="text"
className="form-control"
id="name"
placeholder="Name"
onChange={this.handleChange}
/>
<input
type="text"
className="form-control my-2"
id="lastname"
placeholder="Last Name"
onChange={this.handleChange}
/>
<input
type="text"
className="form-control my-2"
id="language"
placeholder="Language"
onChange={this.handleChange}
/>
<input
type="number"
className="form-control my-2"
id="score"
placeholder="Your Score"
onChange={this.handleChange}
/>
<div className="form-check form-check-inline">
<label className="form-check-label" htmlFor="inlineRadio1">
<b style={{ position: "relative", top: -2 }}> Male</b>
</label>
<input
className="form-check-input mx-2"
type="radio"
value="male"
name="gender"
onChange={this.handleChange}
></input>
</div>
<div className="form-check form-check-inline">
<label className="form-check-label" htmlFor="inlineRadio1">
<b style={{ position: "relative", top: -2 }}> Female</b>
</label>
<input
className="form-check-input mx-2"
type="radio"
name="gender"
value="female"
onChange={this.handleChange}
></input>
</div>
<br />
<button className="btn btn-outline-info btn-md mt-2">Add</button>
</div>
</fieldset>
</form>
</div>
);
}
}
export default AddUser;
it prints undefined I don't know what's the problem
You can pass the data through props and get the data from child.
getDataFromUserList() is a props that will recieve the value from the child.
constructor(props){
super(props);
this.state = {
users: [
{
name: "ali",
lastname: "ahmadi",
language: "python",
gender: "male",
score: 100,
},
{
name: "Ahmad",
lastname: "moradi",
language: "JavaScript",
gender: "male",
score: 90,
},
],
};
this.getDataFromUserList = this.getDataFromUserList.bind(this)
}
getDataFromUserList(data){
// Will get the value in data from the child
console.log(data);
}
<UserList users={this.state.users} removeUser={this.removeUser} getDataFromUserList={this.getDataFromUserList}/>
In the userlist page the function in user getDataFromUserList will get as a props.This props is again passed AddUser component as props name getDataFromAddUser
const UserList = (props) => {
const { users } = props;
console.log(users);
return (
<div className="container">
<h1 className="text-center mt-4" style={{ fontFamily: "tahoma" }}>
All Users
</h1>
<AddUser getDataFromAddUser={(data) => { props.getDataFromUserList(data)}} />
</div>
);
};
export default UserList;
In the AddUser component the state value set from the form is passed through userlist component using props.From the userlist component the data is passed to the user. You will get the value in addUser at the user component at getDataFromUserList() function
<button className="btn btn-outline-info btn-md mt-2" onClick={() => { this.props.getDataFromAddUser(this.state)}}>Add</button>
You have a typo here,
import UserList from "./userList";
It should be
import UserList from "./UserList";
I am created a dynamic form in react.js but i can not type anything value in input because onchnage function not working i don't know why i tried a lot of times but i am getting failed and adding form and deleting form is working all right only input value not working here is my code and codesandbox link https://codesandbox.io/s/reactdynamicform-02cho .
import React, { Component } from "react";
import "bootstrap/dist/css/bootstrap.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
inputFields: [
{
firstName: "",
lastName: ""
}
]
};
}
handleAddFields = () => {
const values = this.state.inputFields;
values.push({ firstName: "", lastName: "" });
this.setState({
values
});
};
handleRemoveFields = index => {
const values = this.state.inputFields;
values.splice(index, 1);
this.setState({
values
});
};
async onChange(e, index) {
if (
["firstName","lastName"].includes(e.target.name)
) {
let cats = [...this.state.inputFields];
cats[index][e.target.name] = e.target.value;
await this.setState({
cats
});
}else{
this.setState({ [e.target.name]: e.target.value.toUpperCase() });
}
console.log(this.state.inputFields);
}
handleSubmit = e => {
e.preventDefault();
console.log("inputFields", this.state.inputFields);
};
render() {
return (
<>
<h1>Dynamic Form Fields in React</h1>
<form onSubmit={this.handleSubmit.bind(this)}>
<div className="form-row">
{this.state.inputFields.map((inputField, index) => (
<div key={`${inputField}~${index}`}>
<div className="form-group col-sm-6">
<label htmlFor="firstName">First Name</label>
<input
type="text"
className="form-control"
id="firstName"
name="firstName"
value={inputField.firstName}
onChange={this.onChange.bind(index)}
/>
</div>
<div className="form-group col-sm-4">
<label htmlFor="lastName">Last Name</label>
<input
type="text"
className="form-control"
id="lastName"
name="lastName"
value={inputField.lastName}
onChange={this.onChange.bind(index)}
/>
</div>
<div className="form-group col-sm-2">
<button
className="btn btn-link"
type="button"
onClick={() => this.handleRemoveFields(index)}
>
-
</button>
<button
className="btn btn-link"
type="button"
onClick={() => this.handleAddFields()}
>
+
</button>
</div>
</div>
))}
</div>
<div className="submit-button">
<button
className="btn btn-primary mr-2"
type="submit"
// onSubmit={this.handleSubmit}
>
Save
</button>
</div>
<br />
<pre>{JSON.stringify(this.state.inputFields, null, 2)}</pre>
</form>
</>
);
}
}
export default App;
You approach is not the correct. Use object to contain form values
state = {
inputFields: { firstName: '', lastName: '' }
}
onChange = (e) => {
const { name, value } = e.target;
this.setState(prevState => ({ inputFields: { ...prevState.inputFields, [name]: value } }));
}
// in jsx
<input name="firstName" onChange={this.onChange} />
try this
onChange={(e)=>{this.onChange(e, index)}}
instead of
onChange={this.onChange.bind(index)}
1) Since your inputFields state is an array, you can't just call this.state.inputFields.firstName and even less inputField.firstName.
You have to call this.state.inputsFields[0].firstName.
2) If you want the index AND the event, you have to pass the onChange event like this :
<input
type="text"
className="form-control"
id="lastName"
name="lastName"
onChange={event => this.handleChange(event, index)}
/>
handleChange = (event, index) => {
console.log(event.currentTarget.value, index);
};
// output : {whatever you type} {index of the form}
// exemple : "hello 1"
I have this code, but I can't make it work. The input lines simply won't accept anything. I tried searching all over the place to no avail, so i decided to finally ask the question.
P.S. I am new to react
class App extends React.Component {
state = { inputValue: [{item:'', name:''}] }
handleChange = e => {
const newValue = [...this.state.inputValue];
newValue[0][e.target.name] = e.target.value;
this.setState({inputValue: newValue});
}
render(){
return(
<div className='container jumbotron'>
<div className="row">
<div className="col">
<FirstInput handleChange={this.handleChange} inputValue={this.state.inputValue[0].name}/>
</div>
<div className="col">
<SecondInput handleChange={this.handleChange} inputValue={this.state.inputValue[0].name}/>
</div>
</div>
</div>
);
}
}
const FirstInput = (props) => (
<div>
<label>First Input</label>
<input className="form-control" onChange={props.handleChange} value={props.inputValue}/>
</div>
)
const SecondInput = ({inputValue, handleChange}) => (
<div>
<label>Second Input</label>
<input className="form-control" onChange={handleChange} value={inputValue}/>
</div>
)
ReactDOM.render(<App />, document.getElementById('root'));
Sorry, I forgot to mention that I want to maintain the array as an array of object. The goal is to have first input and second input be the same value. Meaning, changing one input will make the other input the same.
You don't have name attribute defined on your Input elements and hence the value doesn't change. Update your code to
class App extends React.Component {
state = { inputValue: [{ item: '', name: '' }, { item: '', name: '' }] }
handleChange = e => {
const newValue = [...this.state.inputValue];
newValue[0][e.target.name] = e.target.value;
this.setState({ inputValue: newValue });
}
render() {
return (
<div className='container jumbotron'>
<div className="row">
<div className="col">
<FirstInput handleChange={this.handleChange} inputValue={this.state.inputValue[0].name} />
</div>
<div className="col">
<SecondInput handleChange={this.handleChange} inputValue={this.state.inputValue[0].item} />
</div>
</div>
</div>
);
}
}
const FirstInput = (props) => (
<div>
<label>First Input</label>
<input className="form-control" name="name" onChange={props.handleChange} value={props.inputValue} />
</div>
)
const SecondInput = ({ inputValue, handleChange }) => (
<div>
<label>Second Input</label>
<input className="form-control" name="item" onChange={handleChange} value={inputValue} />
</div>
)
You are overwriting your state. inputValue: [{item:'', name:''}] is an array, and handleChange you try to assign string value.
Your code should look like this one:
class App extends React.Component {
state = {
firstInput: '',
secondInput: ''
}
handleChange = e => {
this.setState({
[e.target.name]: e.target.value;
});
}
render(){
return(
<div className='container jumbotron'>
<div className="row">
<div className="col">
<Input
label="First Input"
name="firstInput"
handleChange={this.handleChange}
inputValue={firstInput}/>
</div>
<div className="col">
<Input
label="First Input"
name="secondInput"
handleChange={this.handleChange}
inputValue={secondInput}/>
</div>
</div>
</div>
);
}
}
const Input = (props) => (
<div>
{props.label && <label>{props.label}</label>}
<input
className="form-control"
onChange={props.handleChange}
name={props.name}
value={props.inputValue}/>
</div>
)
ReactDOM.render(<App />, document.getElementById('root'));
This question already has answers here:
ReactJS this.state null
(5 answers)
Closed 6 years ago.
I have a component in react that is a simple form, I have a function that looks if there is a change in any of the form elements and then sets the state of the form element being edited. In the handleChange function when I do console.log(this.state) I see the exact thing I expect, the correct keys eg (name, teamName etc) with the values in I have entered in the form.
However when I click submit and it calls the function nextStep I get an error message saying this.state.name is null, am I missing something here?
Here is my component.
var ReactDom = require('react-dom');
const uuid = require('uuid/v1');
import {postDataTest} from "../actions/postData";
import TeamSelectBox from "./TeamSelectBox";
import React, {Component, PropTypes} from "react";
class PlayerForm extends Component {
constructor(props) {
super(props);
this.state = {
name: '',
teamName: '',
bio: '',
teamId: ''
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(name, event) {
this.setState({[name]: event.target.value});
console.log(this.state);
}
nextStep(e) {
e.preventDefault();
// Get values via this.refs
var player = {
id: uuid(),
name: this.state.name,
teamName: this.state.teamName,
bio: this.state.bio,
teamId: this.state.teamId
};
postDataTest(player);
}
render() {
return (
<div className="row">
<div className="col-md-6">
<div className="panel">
<div className="panel-heading">
<h1>Add Player</h1>
</div>
<div className="panel-body">
<form className="form-horizontal">
<div className="form-group">
<label className="control-label">Name</label>
<input type="text" className="form-control" ref="name" defaultValue={this.state.name} onChange={this.handleChange.bind(this, 'name')}/>
</div>
<div className="form-group">
<label className="control-label">Team Name</label>
<input type="text" className="form-control" ref="teamName" defaultValue={this.state.teamName} onChange={this.handleChange.bind(this, 'teamName')}/>
</div>
<TeamSelectBox state={this.state.teamId} onChange={this.handleChange.bind(this, 'teamId')}/>
<div className="form-group">
<label className="control-label">Bio</label>
<input type="textarea" className="form-control" ref="bio" defaultValue={this.state.bio} onChange={this.handleChange.bind(this, 'bio')}/>
</div>
<div className="bs-component">
<button className="btn btn-md btn-default btn-block" onClick={this.nextStep}>Save & Continue</button>
</div>
</form>
</div>
</div>
</div>
</div>
)
}
}
module.exports = PlayerForm;
setState doesn't mutate the state immediately and hence you must make use of callback in setState to log the updated value
handleChange(name, event) {
this.setState({[name]: event.target.value}, function() {
console.log(this.state);
});
}
Also you did not bind the nextStep function. You should do that in the constructor or any other way you prefer
class PlayerForm extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
teamName: '',
bio: '',
teamId: ''
};
this.handleChange = this.handleChange.bind(this);
this.nextStep = this.nextStep.bind(this);
}
handleChange(name, event) {
this.setState({[name]: event.target.value});
console.log(this.state);
}
nextStep(e) {
e.preventDefault();
// Get values via this.refs
var player = {
id: "9879",
name: this.state.name,
teamName: this.state.teamName,
bio: this.state.bio,
teamId: this.state.teamId
};
postDataTest(player);
}
render() {
return (
<div className="row">
<div className="col-md-6">
<div className="panel">
<div className="panel-heading">
<h1>Add Player</h1>
</div>
<div className="panel-body">
<form className="form-horizontal">
<div className="form-group">
<label className="control-label">Name</label>
<input type="text" className="form-control" ref="name" defaultValue={this.state.name} onChange={this.handleChange.bind(this, 'name')}/>
</div>
<div className="form-group">
<label className="control-label">Team Name</label>
<input type="text" className="form-control" ref="teamName" defaultValue={this.state.teamName} onChange={this.handleChange.bind(this, 'teamName')}/>
</div>
<div className="form-group">
<label className="control-label">Bio</label>
<input type="textarea" className="form-control" ref="bio" defaultValue={this.state.bio} onChange={this.handleChange.bind(this, 'bio')}/>
</div>
<div className="bs-component">
<button className="btn btn-md btn-default btn-block" onClick={this.nextStep}>Save & Continue</button>
</div>
</form>
</div>
</div>
</div>
</div>
)
}
}
ReactDOM.render(<PlayerForm/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.0.0/react-dom.min.js"></script>
<div id="app"></div>