I have this app that adds products and updates it.As it is, the product form can be submitted without a name, and it creates a new product with a blank line in the name column.how do i Add a validation message so that it requires a 'name' field before submitting the results, and shows a message if you try to submit the form without a name value.
import React from 'react';
const RESET_VALUES = {id: '', category: '', price: '', stocked: false, name: ''};
class ProductForm extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSave = this.handleSave.bind(this);
this.state = {
product: Object.assign({}, RESET_VALUES),
errors: {}
};
}
handleChange(e) {
const target = e.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState((prevState) => {
prevState.product[name] = value;
return { product: prevState.product };
});
}
handleSave(e) {
this.props.onSave(this.state.product);
this.setState({
product: Object.assign({}, RESET_VALUES),
errors: {}
});
e.preventDefault();
}
render() {
return (
<form>
<h3>Enter a new product</h3>
<p>
<label>
Name
<br />
<input type="text" name="name" onChange={this.handleChange} value={this.state.product.name}/>
</label>
</p>
<p>
<label>
Category
<br />
<input type="text" name="category" onChange={this.handleChange} value={this.state.product.category} />
</label>
</p>
<p>
<label>
Price
<br />
<input type="text" name="price" onChange={this.handleChange} value={this.state.product.price} />
</label>
</p>
<p>
<label>
<input type="checkbox" name="stocked" onChange={this.handleChange} checked={this.state.product.stocked}/>
In stock?
</label>
</p>
<input type="submit" value="Save" onClick={this.handleSave}/>
</form>
);
}
}
export default ProductForm;
<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>
Set errors to null by default.
this.state = {
product: Object.assign({}, RESET_VALUES),
errors: null
};
Update your handleSave to something like this:
handleSave(e) {
e.preventDefault();
if (this.state.product.name.trim() === '') {
this.setState({errors: {name: 'Please fill name'}});
return;
}
this.props.onSave(this.state.product);
this.setState({
product: Object.assign({}, RESET_VALUES),
errors: null
});
}
And then in Form render method under Input field show error.
<label>
Name
<br />
<input type="text" name="name" onChange={this.handleChange} value={this.state.product.name}/>
{this.state.errors && <p>{this.state.errors.name}</p>}
</label>
Working example https://codesandbox.io/s/cocky-ride-2p8ym
Related
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.
I'd like to write an unordered list compiled from a form's input values into a <ul> when I click on the Submit button. It's a controlled form in a class based component. Unfortunately I haven't found out how I can achieve it without hooks.
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
email: "",
message: "",
demo: "",
};
this.changeHandler = this.changeHandler.bind(this);
this.submitFormHandler = this.submitFormHandler.bind(this);
}
changeHandler = (e) => {
this.setState = {
name: e.target.value,
email: e.target.value,
message: e.target.value,
demo: `
<li>${this.state.name}</li>
<li>${this.state.email}</li>
<li>${this.state.message}</li> `
};
this.setState(this.setState)
};
submitFormHandler = (e) => {
e.preventDefault();
// I guess the solution will be here somehow
};
render() {
return (
<form onSubmit={this.submitFormHandler} >
<label htmlFor="name">Name:</label> <br/>
<input id="name" type="text" value={this.state.name} onChange={this.changeHandler} />
<br/>
<label htmlFor="mail">E-mail:</label> <br/>
<input id="mail" type="email" value={this.state.email} onChange={this.changeHandler} />
<br/>
<label htmlFor="msg">Message:</label> <br/>
<textarea id="msg" type="email" value={this.state.message} onChange={this.changeHandler} />
<h4>Values of the inputs:</h4>
<ul id="demo">
{this.state.demo} {/* the list would be here! */}
</ul>
<button type="submit">Submit</button>
</form>
); }
};
To show something when it is submitted I would make a isSubmitted flag. Also you controlled inputs were not working. When inputs ids are corresponding with names in state we can easier handle them in onChange handler function. Also when it is submitted we can prevent user from updating data in changeHandler with early return. So I fixed it in code below:
// import React from 'react';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
name: '',
email: '',
message: '',
isSubmitted: false,
};
this.changeHandler = this.changeHandler.bind(this);
this.submitFormHandler = this.submitFormHandler.bind(this);
}
changeHandler = ({ target }) => {
if (this.state.isSubmitted) return;
this.setState({ [target.id]: target.value });
};
submitFormHandler = (e) => {
e.preventDefault();
this.setState({ isSubmitted: true });
};
render() {
return (
<div>
<form onSubmit={this.submitFormHandler}>
<label htmlFor="name">Name:</label> <br />
<input
id="name"
type="text"
value={this.state.name}
onChange={this.changeHandler}
/>
<br />
<label htmlFor="email">E-mail:</label> <br />
<input
id="email"
type="email"
value={this.state.email}
onChange={this.changeHandler}
/>
<br />
<label htmlFor="message">Message:</label> <br />
<textarea
id="message"
type="email"
value={this.state.message}
onChange={this.changeHandler}
/>
<br />
<button type="submit">Submit</button>
</form>
{this.state.isSubmitted && (
<React.Fragment>
<h4>Values of the inputs:</h4>
<ul>
<li>{this.state.name}</li>
<li>{this.state.email}</li>
<li>{this.state.message}</li>
</ul>
</React.Fragment>
)}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I have three states which consists of name, age and email which its values are manually specficied in order to display the values in the three input text fields.
However, I want to make all of the three values from the input text field editable as well.
I'm receving an error age is not defined. May I know why?
Here is the link which used to run the code below:
https://stackblitz.com/edit/react-zyeeed
import React, { Component } from 'react';
import { render } from 'react-dom';
class Info extends Component {
constructor(props) {
super(props);
state = {
name = "Jack Sparrow",
age = "52",
email = "jacksparrow52#gmail.com"
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
let newState = {...this.state};
newState[e.target.name] = e.target.name
this.setState({
newState
})
}
render() {
return (
<div>
<input type="text" name="name" value={this.state.name} placeholder="Enter your name..." onChange={(e) => this.handleChange(e)} />
<br /> <br />
<input type="text" name="age" value={this.state.age} placeholder="Enter your age..." onChange={(e) => this.handleChange(e)} />
<br /> <br />
<input type="text" name="email" value={this.state.email} placeholder="Enter your email..." onChange={(e) => this.handleChange(e)} />
<h3>Output states:</h3>
<p id="name">Entered Name: {this.state.name}</p>
<p id="age">Entered Age: {this.state.age}</p>
<p id="age">Entered Email: {this.state.email}</p>
</div>
);
}
}
render(<Info />, document.getElementById('root'));
There are a few things missing.
Need to use this.state
Correct the assignment of state properties
Change newState[e.target.name] = e.target.name to newState[e.target.name] = e.target.value
Change this.setState({ newState }) to this.setState(newState) or this.setState({ ...newState })
I think that covers it. I made a working example. Hope that helps!
Missing a this
this.state = {
name = "Jack Sparrow",
age = "52",
email = "jacksparrow52#gmail.com"
};
I have a problem of trying to make the input text field editable.
Currently, I am unable to edit the values of the input text field where i can remove or add new characters to the value in the input text field.
I have set the values statically in the state objects but I also want to edit the state values from the input text field.
How can I edit the code below to make the value editable?
import React, { Component } from 'react';
import { render } from 'react-dom';
class Info extends Component {
constructor(props) {
super(props);
this.state = {
name: "Jack Sparrow",
age: "52",
email: "jacksparrow52#gmail.com"
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
let newState = {...this.state};
newState[e.target.name] = e.target.name
this.setState({
...newState
})
}
render() {
return (
<div>
<input type="text" name="name" value={this.state.name} placeholder="Enter your name..." onChange={(e) => this.handleChange(e)} />
<br /> <br />
<input type="text" name="age" value={this.state.age} placeholder="Enter your age..." onChange={(e) => this.handleChange(e)} />
<br /> <br />
<input type="text" name="email" value={this.state.email} placeholder="Enter your email..." onChange={(e) => this.handleChange(e)} />
<h3>Output states:</h3>
<p id="name">Entered Name: {this.state.name}</p>
<p id="age">Entered Age: {this.state.age}</p>
<p id="email">Entered Email: {this.state.email}</p>
</div>
);
}
}
render(<Info />, document.getElementById('root'));
You are setting the state to the target input name. Fix this line
newState[e.target.name] = e.target.name
with (notice e.target.value)
newState[e.target.name] = e.target.value
Change your input field like this, Add input field name and bind handle Change inside the input field. Now you do not want to bind handle Change in constructor.
<input type="text" name="name" value={this.state.name} placeholder="Enter your name..." onChange={this.handelChange.bind(this, 'name')} />
Now replace handle change function,
handelChange(field, event) {
this.setState({
[field]: event.target.value
})
}
I hope this helps, I created a codesandbox with this solution
https://codesandbox.io/s/editable-inputs-m4fqk6?file=/src/App.tsx:256-2201
import { useState } from "react";
interface infoProfile {
name: string;
email: string;
}
const App = () => {
const [editCancel, setEditCancel] = useState(false);
const [value, setValue] = useState<infoProfile>({
name: "Anakin Skywalker",
email: "anakin#empire.com"
});
const onClick = (): void => {
setValue({ email: value.email, name: value.name });
setEditCancel(false);
};
return (
<>
<h1>Editable Inputs</h1>
<div>
<button onClick={() => setEditCancel(!editCancel)}>
{editCancel ? "Cancel" : "Edit"}
</button>
{editCancel && <button onClick={onClick}>Save</button>}
</div>
{!editCancel && (
<div>
<h2>Name</h2>
<div>{value.name}</div>
<h2>Email</h2>
<div>{value.email}</div>
</div>
)}
{editCancel && (
<div>
<h2>Name</h2>
<input
value={value.name}
onChange={(e) =>
setValue({ name: e.target.value, email: value.email })
}
/>
<h2>Email</h2>
<input
value={value.email}
onChange={(e) =>
setValue({ email: e.target.value, name: value.name })
}
/>
</div>
)}
</>
);
};
export default App;
This is the very beginning of my react learning. I am facing some issue about input field. If I use value field in form then this input filed become unchangeable. Like I can't write anything on that filed. But while I remove value filed it work fine.
Here is my code
import React, { Component } from 'react';
export class Registration extends Component{
constructor(){
super();
this.state = {
name: '',
email: '',
password: '',
};
this.onChange = this.onChange.bind(this);
}
onChange(e){
this.setState = ({
name: e.target.value
});
}
render(){
return(
<div className="registration">
<form name="registration" id="registration" >
<div className="userName">
<label> Name : </label>
<input name="name" type="text" onChange={this.onChange} value={this.state.name}/>
<br/>
</div>
<label> Email : </label>
<input name="email" type="email" />
<br/>
<label> Password : </label>
<input name="password" type="password" />
<br/>
</form>
</div>
);
}
}
On the name input field I am using value attribute. This is making this issue.
The problem is that you accidentally wrote
this.setState = ({
name: e.target.value
});
Instead of
this.setState({
name: e.target.value
});
The = is incorrect, as you're trying to call a method and not declare a variable with a dictionary.
Your this.setState is set wrong.
class Registration extends React.Component {
constructor() {
super();
this.state = {
name: "",
email: "",
password: ""
};
this.onChange = this.onChange.bind(this);
}
onChange(e) {
this.setState({
name: e.target.value
});
}
render() {
return (
<div className="registration">
<form name="registration" id="registration">
<div className="userName">
<label> Name : </label>
<input
name="name"
type="text"
onChange={e => this.onChange(e)}
value={this.state.name}
/>
<br />
</div>
<label> Email : </label>
<input name="email" type="email" />
<br />
<label> Password : </label>
<input name="password" type="password" />
<br />
</form>
</div>
);
}
}
ReactDOM.render(<Registration />, document.getElementById("app"));
<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>
<div id="app" />