How do I reset the values in a form in React JS onClick?
class AddFriendForm extends Component {
constructor(props) {
super(props)
this.state = {
firstname: '',
lastname: '',
}
}
render() {
const { addFriend } = this.props
const setFirstName = add => this.setState({ firstname: add.target.value })
const setLastName = add => this.setState({ lastname: add.target.value })
return (
<div>
<div>
<Label label="First Name" />
<Field onChange={setFirstName} />
<Label label="Last Name" />
<Field onChange={setLastName} />
<SecondaryButton
name="Search"
onClick={() => addFriend(this.state)}
/>
<SecondaryButton
name="Reset"
onClick={() => ???}
/>
</div>
</div>
)
}
}
When the user presses the Reset button, I want an onClick event that resets all the fields in the form to blank. Is there a single line of code to do this?
First, create a function called resetForm
resetForm = () => {
this.setState({
...this.state,
firstname: '',
lastname: ''
})
}
Then trigger the function when reset button is clicked
onClick={this.resetForm}
Cheers mate
EDIT:
You have to assign the values to "Field" using value={this.state.firstname}
<Field value={this.state.firstname} onChange={...
Small tip: dont define your functions in your jsx code.
You can do this simply like this.
Before the render() add below part. This is a function to reset the fields.
reset = () => {
this.setState({ firstname: ''})
this.setState({ lastname: ''})
}
And this where the function is called. (In Button onPress.)
<Button
title='reset'
style={styles.button}
onPress={this.reset}
>
</Button>
Note:- use this one in functional component.
const handleReset = (e) => {
e.preventDefault();
setState(prevState => ({
...prevState,
name: '',
email: '',
password: ''
}))
}
handleReset = () => {
setState(({
name: '',
email: '',
}))
}
Related
So, I have a data persistence issue with my form inputs.
If I modify all inputs everything is fine.
But if an input is left empty, its previous data is erased when I submit. I need suggestions for my handleChange to keep data even when an input is not modified.
I tried this but it failed too :
handleChange = e => {
e.persist();
this.setState(prevState => ({
product: { ...prevState.product, [e.target.name]: e.target.value }
}))
}
Here is my EditForm, thanks for your help.
EditForm.js
export default class EditForm extends Component {
constructor(props) {
super(props);
this.state = { product: [] };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
};
componentDidMount = () => {
axios
.get(`/products/edit-form/${this.props.match.params.id}`)
.then(response => {
console.log(response.data.products);
this.setState({
product: response.data.products
})
});
};
handleChange(e) {
console.log(e.target.name);
this.setState({[e.target.name]: e.target.value})
}
handleSubmit(e) {
const data = {
id: this.props.match.params.id,
reference: this.state.reference,
designation: this.state.designation
}
e.preventDefault();
console.log(data);
axios
.post(`/products/${data.id}`, data )
.then(res => console.log(res))
.catch(err => console.log(err));
};
renderForm() {
return this.state.product.map((product, index) => {
const { id,reference,designation } = product
return(
<>
<Form className="post" onSubmit={this.handleSubmit}>
<Form.Row>
<Form.Group as={Col} controlId="formGridReference">
<Form.Label>Reference</Form.Label>
<Form.Control type="text" value={this.state.product.reference}
onChange={this.handleChange} name="reference" placeholder={reference}/>
</Form.Group>
<Form.Group as={Col} controlId="formGridDesignation">
<Form.Label>Designation</Form.Label>
<Form.Control type="text" value={this.state.product.designation}
onChange={this.handleChange} name="designation" placeholder={designation}/>
</Form.Group>
</Form.Row>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</>
);
})
}
render() {
return (
<div>
<h1>Formulaire de modification</h1>
{this.renderForm()}
</div>
);
}
}```
In your EditForm.js, inside handleChange(), you have to maintain your previous state. You can do so by creating a copy of your state. Then use the copy to update your state property values and in the end, use this.setState();
Example:
const state = this.state;
state['Your property'] = 'value';
...
...
this.setState(state);
This question already has answers here:
Removing element from array in component state
(11 answers)
Closed 3 years ago.
I have a names list which contains 3 names. On clicking any 1, you can edit and save. That value updates to the list. Now I can add how many ever names I want but I am not able to delete/remove any.
This is how it looks in the beginning
On clicking a name (the whole container) it looks like this
I am able to add the new name back to the div like this
And I can add as many as I want, like this like this
Now I want to be able to click on the cross icon and remove the whole element I want. It should go be gone from the page. The other elements should take its place from top to bottom. Remove/delete functionality should be on input and the div with names in it.
Names Component (Names are extracted from this to the one below)
import Sukhdev from '../../../src/components/sukhdev';
import React from 'react';
export default { title: 'Sukhdev' };
const names = [{
firstName: "Mahatma",
lastName: "Gandhi"
}, {
firstName: "Shivaji",
lastName: "Maharaj"
}, {
firstName: "Bhagat",
lastName: "Singh"
},
]
export const sukhdev = () => {
return(
<Sukhdev names={names}/>
)
}
Parent Component
import React, { Component } from 'react';
import FirstName from './firstName';
import LastName from './lastName';
import TextArea from './textArea'
import styles from './styles';
export default class Sukhdev extends Component {
constructor(props) {
super(props);
const {names} = this.props;
const updatedNames = names.map((name) => ({...name, ...{isEditable: false}}));
this.state = {
userNames: updatedNames
}
}
inputNamesHandler = (namesIndex) => {
const updatedUserNameDetails = [...this.state.userNames];
updatedUserNameDetails[namesIndex].isEditable = true;
this.setState({userNames: updatedUserNameDetails})
}
saveButton = (inputValue, index) => {
const {userNames} = this.state;
const newNames = [...userNames];
newNames[index] = {...newNames[index], isEditable: false, firstName: inputValue, lastName: ''};
this.setState({
userNames: newNames
})
}
addChild = () => {
const createInputs = [...this.state.userNames];
createInputs.push({firstName: '', lastName: '', isEditable: true});
this.setState({
userNames: createInputs
})
}
------> // This is where the changes need to be made
deleteRow = (index) => {
const postDelete = [...this.state.userNames];
postDelete.slice(index, 1);
this.setState({
userNames: postDelete
})
}
render() {
return <div>
<h1>Names</h1>
<button onClick={this.addChild} style={styles.button}>Add New</button>
<div>
{this.state.userNames.map((nameDetails, index) => {
if(nameDetails.isEditable) {
return <div>
<TextArea clicked={(name) => this.saveButton(name, index)}/>
</div>;
} else {
return <div style={styles.namesContainer}>
<div onClick={() => this.inputNamesHandler(index)} style={styles.innerContainerComponent}>
<div style={styles.firstMargin}><FirstName firstName={nameDetails.firstName}></FirstName></div>
<div><LastName lastName={nameDetails.lastName}></LastName></div>
</div>
<img src={require('../../images/cancel.png')} style={styles.crossBtn} onClick={() => this.deleteRow(index)} />
</div>
}
})}
</div>
</div>
}
}
Textarea/Input Component
import React, { Component } from "react";
import styles from './styles'
export default class TextArea extends Component {
constructor(props) {
super(props);
this.state = {value:''}
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
render() {
return (
<div>
<div style={styles.inputContainer}>
<input type="text" style={styles.textField} value={this.state.value} onChange={this.handleChange}></input>
<button type="submit" style={styles.saveButton} onClick={() => this.props.clicked(this.state.value)}>Save</button>
<img src={require('../../images/cancel.png')} style={styles.crossBtn} />
</div>
</div>
)
}
}
First name and last name are imported by parent component in this way
import React, {Component} from 'react';
export default class FirstName extends Component {
render() {
return <div>{this.props.firstName}</div>
}
}
Last name is also like the code given above.
slice does not modify the original array, but returns a new array with the modified values. You need to assign it to a new variable or use a different method of deleting the value.
let newArray = postDelete.slice(index, index + 1);
this.setState({
userNames: newArray
})
In fact, since slice does not mutate the array, you could simplify to this:
this.setState((prevState) => ({
userNames: prevState.userNames.slice(index, index + 1)
)})
However, to accomplish this specific task, you should use a different method like filter
this.setState((prevState) => ({
userNames: prevState.userNames.filter((v,i) => i != index)
)})
This will iterate through the array and filter out all that don't meet the condition. The first argument is the current value and the second is the index. So we only want to keep the values that do not match our index variable.
class App extends React.Component {
state = {
users: [
{
firstName: "Lionel",
lastName: "Messi"
},
{
firstName: "Cristiano",
lastName: "Ronaldo"
},
{
firstName: "Neymar",
lastName: "Jr."
},
{
firstName: "Zlatan",
lastName: "Ibrahimovic"
},
{
firstName: "Ricardo",
lastName: "Kaka"
}
]
};
updateUsers = (updatedUser, index) => {
var users = [...this.state.users];
users[index] = updatedUser;
this.setState({
users
});
};
deleteUser = index => {
var users = [...this.state.users];
users.splice(index, 1);
this.setState({
users
});
};
render() {
return (
<div>
{this.state.users.map((user, index) => {
return (
<PlayerBox
user={user}
key={Math.random()}
index={index}
updateUsers={this.updateUsers}
deleteUser={this.deleteUser}
/>
);
})}
<h1> {JSON.stringify(this.state.users)} </h1>
</div>
);
}
}
class PlayerBox extends React.Component {
state = {
editMode: false,
firstName: "",
lastName: ""
};
componentDidMount() {
const { firstName, lastName } = this.props.user;
this.setState({
firstName,
lastName
});
}
updateParent = () => {
const { index, updateUsers } = this.props;
updateUsers(
{
firstName: this.state.firstName,
lastName: this.state.lastName
},
index
);
this.setState({
editMode: false
});
};
deleteUser = () => {
const { deleteUser, index } = this.props;
this.setState({
editMode: false
});
deleteUser(index);
};
render() {
const { firstName, lastName } = this.props.user;
return this.state.editMode ? (
<div>
<div>
<input
type="text"
value={this.state.firstName}
onChange={e =>
this.setState({
firstName: e.target.value
})
}
/>
<input
type="text"
value={this.state.lastName}
onChange={e =>
this.setState({
lastName: e.target.value
})
}
/>
<button type="submit" onClick={this.updateParent}>
Save
</button>
<button onClick={this.deleteUser}> Delete </button>
</div>
</div>
) : (
<div
onClick={() =>
this.setState({
editMode: true
})
}
>
{firstName} {lastName}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<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>
<div id="root"></div>
I'm building an exercise tracker app in React.
Right now, I'm building the CreateExercise component to submit a form, so I need to update the states of each value. In order to do so, I created methods to handle those changes (onChangeUsername, onChangeDescription, onChangeDuration etc...) but I don't really like to repeat methods like this.
How to write a more generic method to handle this task ?
class CreateExercise extends Component {
constructor(props) {
super(props);
this.state = {
username: '',
description: '',
duration: 0,
date: new Date(),
users: []
}
}
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);
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((user) => (
<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:</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-groupe'>
<input
type='submit'
value='Create Exercise Log'
className='btn btn-primary'
/>
</div>
</form>
</div>
);
}
}
export default CreateExercise;
Using partial application, create a function in your component that takes a field name, and returns a function that sets the state:
onChangeValue = field => e => {
this.setState({
[field]: e.target.value
});
};
Usage:
onChangeUsername = onChangeValue('username');
onChangeDescription = onChangeValue('description');
onChangeDuration = onChangeValue('duration');
You extend the idea further to support the onChangeDate as well:
onChangeValue = (field, valueTransformer = e => e.target.value) => e => {
this.setState({
[field]: valueTransformer(e.target.value)
});
};
This doesn't change the other on functions, since the default is to get e.target.value. To use onChangeDate we can now change the valueTransformer:
onChangeDate = onChangeValue('date', v => v);
You can define name for the HTML element, and use that to set value:
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
corresponding JSX element:
<input
type="text"
name="description"
required
className="form-control"
value={this.state.description}
onChange={this.onChange}
/>
I created this.state.data object. Now I need to put this.state.email and this.state.password into this.state.data.email2 and this.state.data.password2
I want to create local storage. To do that I need an object where I could store data. this.state.email and this.state.password are inputs.
class Register extends Component {
constructor(props){
super(props);
this.state = {
email: '',
password: '',
data: {
email2: '',
password2: '',
},
}
// This binding is necessary to make `this` work in the callback
this.handleEmailChange = this.handleEmailChange.bind(this);
this.handlePasswordChange = this.handlePasswordChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleEmailChange = (event) => {
this.setState({email: event.target.value});
}
handlePasswordChange = (event) => {
this.setState({password: event.target.value});
}
handleSubmit = (event) => {
event.preventDefault();
console.log(this.state.email);
console.log(this.state.password);
/*
Take values from input, ant put it into this state data array
*/
// Reset form;
this.setState({
email: '',
password: '',
})
}
When I activate handleSubmit method I expect to take this.state.email, and this.state.password. And put it into object this.state.data
Hope you need to pass this.state.email and this.state.password to this.state.data
You can do that in handleEmailChange and handlePasswordChange itself, and your using arrow functions, so don't need to bind this in constructor.
Check a code below:
class App extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
data: {
email2: '',
password2: '',
},
}
}
handleEmailChange = (event) => {
this.setState({
email: event.target.value,
data: {
...this.state.data,
email2: event.target.value,
}
});
}
handlePasswordChange = (event) => {
this.setState({
password: event.target.value,
data: {
...this.state.data,
password2: event.target.value,
}
});
}
handleSubmit = (event) => {
event.preventDefault();
console.log(this.state.email);
console.log(this.state.password);
console.log('object data');
console.log(this.state.data);
/*
Take values from input, ant put it into this state data array
*/
// Reset form;
this.setState({
email: '',
password: '',
}, () => console.log(this.state))
}
render() {
return (
<div>
<input type="text" onChange={this.handleEmailChange} value={this.state.email} />
<br/><br/>
<input type="text" onChange={this.handlePasswordChange} value={this.state.password} />
<br/><br/>
<button type="button" onClick={this.handleSubmit}>Submit</button>
</div>
);
}
}
Working demo
and don't need to write separate events for similar functionalities, Check the demo once, you can do it like below:
<input type="text" data-field = "email" onChange={this.handleChange} value={this.state.email} />
<input type="text" data-field = "password" onChange={this.handleChange} value={this.state.password} />
and in handleChange
handleChange = (event) => {
this.setState({
[event.target.getAttribute('data-field')]: event.target.value,
data: {
...this.state.data,
[`${event.target.getAttribute('data-field')}2`]: event.target.value,
}
});
}
Hope this helps.
Like this (assuming your setup supports spread operator ... )
handleEmailChange = event => {
this.setState({ email: event.target.value });
this.setState(prevState => ({ data: { ...prevState.data, email2: event.target.value } }));
};
handlePasswordChange = event => {
this.setState({ password: event.target.value });
this.setState(prevState => ({ data: { ...prevState.data, password2: event.target.value } }));
};
You can do like this
handleSubmit = (event) => {
event.preventDefault();
console.log(this.state.email);
console.log(this.state.password);
const {data} = this.state;
data.email2 = this.state.email;
data.password2 = this.state.password;
this.setState({ data });
// Reset form;
this.setState({
email: '',
password: '',
})
}
or without mutating the state (good practice)
this.setState(prevState => ({
data: {
...prevState.data,
[data.email2]: this.state.email
[data.password2]: this.state.password
},
}));
Hi i found an answer to this for a single field form... but what if we have a form with multiple field?
this is fine for disabling it if you have 1 field but it does not work when you want to disable it based on many fields:
getInitialState() {
return {email: ''}
},
handleChange(e) {
this.setState({email: e.target.value})
},
render() {
return <div>
<input name="email" value={this.state.email} onChange={this.handleChange}/>
<button type="button" disabled={!this.state.email}>Button</button>
</div>
}
})
Here is a basic setup for form validation:
getInitialState() {
return {
email: '',
text: '',
emailValid: false, // valid flags for each field
textValid: false,
submitDisabled: true // separate flag for submit
}
},
handleChangeEmail(e) { // separate handler for each field
let emailValid = e.target.value ? true : false; // basic email validation
let submitValid = this.state.textValid && emailvalid // validate total form
this.setState({
email: e.target.value
emailValid: emailValid,
submitDisabled: !submitValid
})
},
handleChangeText(e) { // separate handler for each field
let textValid = e.target.value ? true : false; // basic text validation
let submitValid = this.state.emailValid && textvalid // validate total form
this.setState({
text: '',
textValid: textValid,
submitDisabled: !submitValid
})
},
render() {
return <div>
<input name="email" value={this.state.email} onChange={this.handleChangeEmail}/>
<input name="text" value={this.state.text} onChange={this.handleChangeText}/>
<button type="button" disabled={this.state.submitDisabled}>Button</button>
</div>
}
})
In a more elaborate setup, you may want to put each input field in a separate component. And make the code more DRY (note the duplication in the change handlers).
There are also various solutions for react forms out there, like here.
I would take a little bit different way here...
Instead of setting submitDisabled in every single onChange handler I would hook into lifecycle method to listen to changes.
To be exact into componentWillUpdate(nextProps, nextState). This method is invoked before every change to component - either props change or state change. Here, you can validate your form data and set flag you need - all in one place.
Code example:
componentWillUpdate(nextProps, nextState) {
nextState.invalidData = !(nextState.email && nextState.password);
},
Full working fiddle https://jsfiddle.net/4emdsb28/
This is how I'd do it by only rendering the normal button element if and only if all input fields are filled where all the states for my input elements are true. Else, it will render a disabled button.
Below is an example incorporating the useState hook and creating a component SubmitButton with the if statement.
import React, { useState } from 'react';
export function App() {
const [firstname, setFirstname] = useState('');
const [lastname, setLastname] = useState('');
const [email, setEmail] = useState('');
function SubmitButton(){
if (firstname && lastname && email){
return <button type="button">Button</button>
} else {
return <button type="button" disabled>Button</button>
};
};
return (
<div>
<input value={email} onChange={ e => setEmail(e.target.value)}/>
<input value={firstname} onChange={ e => setFirstname(e.target.value)}/>
<input value={lastname} onChange={ e => setLastname(e.target.value)}/>
<SubmitButton/>
</div>
);
};
This might help. (credits - https://goshakkk.name/form-recipe-disable-submit-button-react/)
import React from "react";
import ReactDOM from "react-dom";
class SignUpForm extends React.Component {
constructor() {
super();
this.state = {
email: "",
password: ""
};
}
handleEmailChange = evt => {
this.setState({ email: evt.target.value });
};
handlePasswordChange = evt => {
this.setState({ password: evt.target.value });
};
handleSubmit = () => {
const { email, password } = this.state;
alert(`Signed up with email: ${email} password: ${password}`);
};
render() {
const { email, password } = this.state;
const isEnabled = email.length > 0 && password.length > 0;
return (
<form onSubmit={this.handleSubmit}>
<input
type="text"
placeholder="Enter email"
value={this.state.email}
onChange={this.handleEmailChange}
/>
<input
type="password"
placeholder="Enter password"
value={this.state.password}
onChange={this.handlePasswordChange}
/>
<button disabled={!isEnabled}>Sign up</button>
</form>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<SignUpForm />, rootElement);
export default function SignUpForm() {
const [firstName, onChangeFirstName] = useState("");
const [lastName, onChangeLastName] = useState("");
const [phoneNumber, onChangePhoneNumber] = useState("");
const areAllFieldsFilled = (firstName != "") && (lastName != "") && (phoneNumber != "")
return (
<Button
title="SUBMIT"
disabled={!areAllFieldsFilled}
onPress={() => {
signIn()
}
}
/>
)
}
Similar approach as Shafie Mukhre's!