how to set state from on change for multiple events react - reactjs

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.

Related

How to display an unordered list into a JSX <ul> element in a React Form using class component

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>

React: rendering multiple user inputs

I have a form containing several inputs and I am handling multiple user inputs but I want to display all the inputs when the submit button is clicked.
What do I need to add/change in my code to display the inputs when they are submitted?
class Planning extends React.Component {
constructor() {
super()
this.state = {
title: '',
goal: '',
tech: '',
features: '',
details: ''
}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange(event) {
this.setState({
[event.target.name]: event.target.value
})
}
handleSubmit(event) {
alert(`Plan: ` )
event.preventDefault()
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div>
<label class="label-title">
Project Title:</label>
<input name="title" id="title" type="text" onChange={this.handleChange}/>
</div>
<div>
<label class="label-goal">
Motivational Goal: </label>
<input name="goal" id="goal" type="text" onChange={this.handleChange}/>
</div>
<div>
<label class="label-tech">
Technologies/tools:</label>
<input name="tech" id="tech" type="text" onChange={this.handleChange}/>
</div>
<div>
<label class="label-features">
Features:</label>
<input name="features" id="features" type="text" onChange={this.handleChange}/>
</div>
<div>
<label class="label-details">
Other details: </label>
<input name="details" id="details" type="text" onChange={this.handleChange}/>
</div>
<input class="submit" type="submit" value="Submit" />
</form>
)
}
}
The values are stored in the state so you could
handleSubmit(event) {
event.preventDefault();
alert(`Plan:\n${JSON.stringify(this.state,null,2)}`);
}
or the more explicit approach
handleSubmit(event) {
const {
title,
goal,
tech,
features,
details
} = this.state;
event.preventDefault();
alert(`Plan:
Title: ${title}
Goal: ${goal}
Tech: ${tech}
Features: ${features}
Details: ${details}
`);
}

Can't input data into form field React

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.

how do i add a validation message in my react component

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

Input filed is not clickable in react while using value attribute

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" />

Resources