emptying the input after submiting a form - reactjs

I'm trying to empty the input tag once I'm updating my state:
state = {
formName: '',
inputs: [],
tempInput: {
inputLabel: '',
inputType: '',
inputValue: ''
}
};
this is my form:
<div className="formG">
<form className="form-maker" onSubmit={this.handleSubmit}>
Label:
<input name="inputLabel" type="text" onChange={this.handleChange} />
Type:
<input name="inputType" type="text" onChange={this.handleChange} />
Value
<input name="inputValue" type="text" onChange={this.handleChange} />
Form Name
<input name="formName" type="text" onChange={this.formName} />
<button>Submit</button>
</form>
that's how I handle the change
handleChange = e => {
const { name, value } = e.target;
this.setState(currentState => ({
tempInput: { ...currentState.tempInput, [name]: value }
}));
};
and I tried to just empty the tempInput but it doesn't work, anybody knows why?
handleSubmit = e => {
e.preventDefault();
const inputs = [...this.state.inputs, this.state.tempInput];
const { tempInput } = this.state;
tempInput.inputLabel = '';
tempInput.inputType = '';
tempInput.inputValue = '';
this.setState({ inputs, tempInput });
};

Your form is an uncontrolled component, so they are not controlled by the state fields. That's why your approach didn't work. Instead you can do e.target.reset() which will clear the entire form. But if you want to reset some input, you can access them and set the .value to "" as I had shown below.
An uncontrolled component works like form elements do outside of React. When a user inputs data into a form field (an input box, dropdown, etc) the updated information is reflected without React needing to do anything. However, this also means that you can’t force the field to have a certain value. From Doc
So your handleSubmit method will look like:
handleSubmit = e => {
e.preventDefault();
const inputs = [...this.state.inputs, this.state.tempInput];
// ....
// The below will reset entire form.
// e.target.reset();
// If you want some of them to empty.
const { elements } = e.target
elements['inputLabel'].value = "";
elements['inputType'].value = "";
elements['inputValue'].value = "";
};
Check the doc of HTMLFormElement.elements

Your input tags are not displaying the value of your state.
1) pull the individual values out of tempInput
2) use the value stored in your state that is then updated by your handleChange.
3) In your handleSubmit function reset your individual values to and empty string.
your handleChange should look like:
handleChange = e => {
const { name, value } = e.target;
this.setState([name]: value);
};
your jsx should look like :
<form className="form-maker" onSubmit={this.handleSubmit}>
Label:
<input name="inputLabel" value={this.state.inputLabel} type="text" onChange={this.handleChange} />
Type:
<input name="inputType" value={this.state.inputType} type="text" onChange={this.handleChange} />
Value
<input name="inputValue" value={this.state.inputType} type="text" onChange={this.handleChange} />
Form Name
<input name="formName" value={this.state.formName} type="text" onChange={this.formName} />
<button>Submit</button>
</form>

You're mutating the original state. You can copy and then only set the state. Just changing the following will work fine for you.
Replace this:
const { tempInput } = this.state;
With this:
const { tempInput } = {...this.state}; // copy the state
Also, be sure to bind the state value in your input elements like this to make them controlled component:
<input name="inputLabel" type="text"
onChange={this.handleChange}
value={this.state.tempInput.inputLabel || ''} />
And your handler should be:
handleChange = e => {
const { value } = e.target;
this.setState({value});
// now, value will correspond to the controlled component
};
Also take care react suggest to use controlled component as far as possible:
In most cases, we recommend using controlled components to implement forms.

Related

how to handle multiple form input with dynamic dropdown render in react Js

I have created a form with multiple input there two dropdown first has option and second one's option changes dynamically based on selection of first dropdown. also i am storing all values in state with submit event.
Okay problem is i am either able to to get values and in state on submit event or either able to dynamically change the option for second dropdown.
But when I am trying to do both or trying to run two function on same onChange event its not trigging is any one can help me out why its not getting trigger and what is the issue.
link : if any one want to see code it dummy code
https://codesandbox.io/s/clever-mendel-ozt8tu?file=/src/App.js:0-1748
App.js
import "./styles.css";
import { useState } from "react";
function App() {
const data = {
first: ["car", "bus"],
second: ["bike", "train"],
third: ["plane", "rocket"]
};
const [option, setOption] = useState([]);
const getInput = (e) => {
let input = e.target.value;
setOption(data[input]);
};
const [values, setValues] = useState({
name: "",
city: "",
category: "",
ride: ""
});
const inputHandle = (e) => {
const { name, value } = e.target;
setValues({
...values,
[name]: value
});
};
const handleSubmit = (e) => {
e.preventDefault();
console.log(values);
};
return (
<>
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="name"
name="name"
value={values.name}
onChange={inputHandle}
/>
<input
type="text"
placeholder="city"
name="city"
value={values.city}
onChange={inputHandle}
/>
<br />
<select
name="category"
values={values.category}
onChange={(e) => {
getInput();
inputHandle();
}}
>
<option defaultValue="category">category</option>
<option value="first">first</option>
<option value="second">Second</option>
<option value="third">Third</option>
</select>
<select name="ride" value={values.ride} onChange={inputHandle}>
{option.map((ele) => (
<option value={ele}>{ele}</option>
))}
</select>
<br />
<button type="submit">Submit</button>
</form>
</>
);
}
export default App;
For the handler of the onChange in the first select, you are taking in the event object e as parameter but not passing it forward in getInput() or inputHandle(). Therefore, you should write something like this:
onChange={(e) => {
getInput(e);
inputHandle(e);
}}
This should do the job. Also, try to use only one function in the handler, like the one you have used for submitting the form.
If you want to combine everything into one handler, you can use the following handler:
const categoryHandler = (event) => {
const selectName = event.target.name;
const selectValue = event.target.value;
setOption(data[selectValue]);
setValues({
...values,
selectName: selectValue
});
};

Add name and email to a state dynamically

I have an event app. Where a user comes add number of people. Then based on the number of people I show input fields for name and email. I am using a for loop to display fields for each used based on number of people.
<input
type="email"
name={`email`}
required
className="form-control"
placeholder="Enter"
onChange={(e) => {
onChange(e, i);
}}
/>
<input
type="text"
name={`firstname`}
required
className="form-control"
placeholder="Enter"
onChange={(e) => {
onChange(e, i);
}}
/>
I have a state:
const [fields, setFields] = useState([{ email: "", firstname: "" }]);
I am trying to update the state dynamically for each user. I am doing something like this:
const onChange = (e, index) => {
const updatedArray = [...fields];
updatedArray.push(([e.currentTarget.name] = e.currentTarget.value));
setFields(updatedArray);
};
Code isn't working. I am not getting a separate object for each user in state array. I am stuck and any help would be appreciated.
the onChange handler should be something like this:
const onChange = (e, index) => {
const inputName = e.currentTarget.name;
const inputValue = e.currentTarget.value;
setFields(prevFields =>
prevFields.map((pF, i) =>
i === index ? { ...pF, [inputName]: inputValue } : pF
)
);
};
functional update is recommended as the new state depends on the old state and the problem with your snippet is you're not using the index to figure out which object to update and the syntax for updating the property in that object is also incorrect.
the two inputs also need a value prop:
<input
type="email"
name={`email`}
required
className="form-control"
placeholder="Enter"
value={field.email}
onChange={(e) => {
onChange(e, i);
}}
/>
<input
type="text"
name={`firstname`}
required
className="form-control"
placeholder="Enter"
value={field.firstname}
onChange={(e) => {
onChange(e, i);
}}
/>
Update:
You need additional code for adding more users, if you want to add a user when a button is clicked:
const addUser = () => {
setFields(prevFields => [
...prevFields,
{
email: "",
firstname: ""
}
]);
};
<button onClick={addUser}>Add User</button>
Here's a React StackBlitz implementing the above solutions

Formik - How do I control the value of another input field automatically when one field changes?

I'm using Formik's useFormik hook to manage my forms in ReactJS. But I don't know how to build a custom onChange handler that works on top of or alongside Formik's handleChange function. I tried building a custom change handler like below but I'm unable to figure out what step to take next.
import React from "react";
import { useFormik } from "formik";
function testForm() {
const { handleChange, values } = useFormik({
initialValues: { title: ``, slug: `` },
onSubmit: ( values ) => console.log( values )
})
const customHandleChange = e => {
// let's suppose title field changed.
const { value } = e.target;
// I can do other functions here, like fetching data from API
store.dispatch( getUserByTitle( value ))
// But I'm trying to set a custom value for the slug field automatically depending on changing title field value
let slugValue = value.toLowerCase()
// handleChange function changes the value of title input. How do I also change slug input?
handleChange(e)
}
return (
<div>
<input type="text"
name="Title"
value={ values.title }
onChange={ customHandleChange }/>
<input type="text"
name="slug"
value={ values.slug }
onChange={ handleChange } />
</div>
)
}
I tried setting value of the slug input directly as follows.
<input type="text"
name="slug"
value={ values.title.toLowerCase() }
onChange={ handleChange } />
But if I do that, I won't be able to type in the field and make a change as the value is strictly set from the title input. Users should also be able to change the slug field value to whatever they want.
Try using setFieldValue:
function testForm() {
const { handleChange, values, setFieldValue } = useFormik({
initialValues: { title: ``, slug: `` },
onSubmit: ( values ) => console.log( values )
})
const customHandleChange = e => {
const { value } = e.target;
setFieldValue('title', value);
setFieldValue('slug', value.toLowerCase());
}
return (
<div>
<input type="text"
name="Title"
value={ values.title }
onChange={ customHandleChange }/>
<input type="text"
name="slug"
value={ values.slug }
onChange={ handleChange } />
</div>
)
}

React js - Use only one state instead of multiple state to handle "event.target.value"

I'm new in React js. I created an app that have input fields and when you click the submit button the value of the input fields will display in console.log depends on the value entered in input fields. The question is can i use only one state to display the following that I entered in the input fields?
this is my code:
constructor () {
super ();
this.state = {
username: '',
password: '',
place: '',
birthPlace: '',
}
}
username = () => {
this.setState({ username: event.target.value })
}
password = () => {
this.setState({ password: event.target.value })
}
place = () => {
this.setState({ place: event.target.value })
}
birthPlace = () => {
this.setState({ birthPlace: event.target.value })
}
What I want to happen is use only one state for username, password, place, birthPlace (if possible) and what I want to happen is when I click the submit button, the value of which I've type in the Input fields should display in console.log
Just for optimization purposes. Thanks for the help
You can use the dictionary objects.
Define your state like this
constructor () {
super ();
this.state = {
formvalues:{}
}
}
and you can update your values by defining any key you want.
this.setState(prevState => ({
formvalues: {
...prevState.formvalues,
[username]: value
}
}))
and you can access any input field based on the key you defines.
`console.log(this.state.formvalues.username)`
constructor () {
super ();
this.state = {
username: '',
password: '',
place: '',
birthPlace: '',
}
}
You can use one method for all values like while using the same state:
handleChange = event => {
const { value, name } = event.target;
this.setState({ [name]: value });
};
Its probably better to use hooks for this, something like the code below would do it
import React , {useState} from 'react'
const myComp = () =>{
const [userDetails, setUserDetails] = useState({})
handleOnChange({target:{value, id}}) =>{
let newState = Object.assign({}, userDetails, {[id]: value})
setUserDetails(newState)
}
return (
<form>
<input type='text' id='name' value={userDetails['name']} onChange={handleOnChange} />
<input type='password' id='password' value={userDetails['password']} onChange={handleOnChange} />
<input type='email' id='email' value={userDetails['email']} onChange={handleOnChange} />
</form>
)
}
You can try this example that uses React hooks:
function App() {
const [state, setState] = React.useState({
username: '',
password: '',
place: '',
birthPlace: '',
});
function handleChange(event) {
const { name, value } = event.target;
console.log(name);
console.log(value);
setState(prevState => ({
...prevState,
[name]: value
}));
}
function handleSubmit(event) {
console.log(state);
event.preventDefault();
}
return (
<form onSubmit={handleSubmit}>
<label>UserName</label>
<input type="text" name="username" value={state.username} onChange={handleChange} /><br />
<label>Password</label>
<input type="password" name="password" value={state.password} onChange={handleChange} /><br />
<label>Place</label>
<input type="text" name="place" value={state.place} onChange={handleChange} /><br />
<label>BirthPlace</label>
<input type="text" name="birthPlace" value={state.birthPlace} onChange={handleChange} /><br />
<input type="submit" value="Submit" />
</form>
);
}
ReactDOM.render(<App />, document.getElementById('root'));
.as-console-wrapper {
height: 80px !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.2/umd/react-dom.production.min.js"></script>
<div id="root"></div>
More info: https://reactjs.org/docs/forms.html
Be aware that setting the state directly with the event.target.value will not always produce the expecting result.
React uses the Synthetic event wrapper and to be able to update the state directly with the event.target.value it uses persist() to make the event persist long enough to be used in the setState() method.
What I suggest doing to use event.target.value in class components is to store the value and then update the state.
So instead of doing this:
username = (event) => {
this.setState({ username: event.target.value })
}
You do this:
username = (event) => {
const value = event.target.value;
this.setState({ username: value })
}
This way the value is preserved long after the event has been fired.
You will notice that I added the event as parameter in the above example. This is to answer your second part of the question regarding on how to update the state. You need to constantly call the username method each time the typed username is changed. You can do this by calling it via the onChange listener:
<input name='username' onChange = {(event) => this.username(event)} />

React. Can I get rid of ref in favor of onChange?

According to React spec:
https://reactjs.org/docs/refs-and-the-dom.html
"There are a few good use cases for refs:
Managing focus, text selection, or media playback.
Triggering imperative animations.
Integrating with third-party DOM libraries.
Avoid using refs for anything that can be done declaratively."
That's why I'm not so sure for now, whether I used ref properly or not in this case:
export let FormInput = createReactClass({
handleInput(e){
e.preventDefault();
const product = this.name.value;
const red = this.red.checked;
this.props.addProduct(product,red);
this.inputForm.reset();
},
render(){
return(
<form className="prod_input" ref={x => this.inputForm = x} onSubmit={this.handleInput}>
<input type="text" ref={x => this.name = x} placeholder="Product name"/>
<input type="checkbox" ref={x => this.red = x} value="true"/>
<input type="submit" hidden/>
</form>
)
}
})
If not, how could it be rearranged in order to replace ref to onChange={}?
You can avoid using refs by making your input fields controlled. Here is an example:
export let FormInput = createReactClass({
constructor(props){
super(props);
this.state = {
name: '',
};
}
handleNameChange(updatedName){
this.setState({ name: updatedName });
}
handleInput(e){
e.preventDefault();
const product = this.state.name;
// ...
this.props.addProduct(product);
this.inputForm.reset();
},
render(){
return (
<form className="prod_input" ref={x => this.inputForm = x} onSubmit={this.handleInput}>
<input type="text" value={this.state.name} placeholder="Product name" onChange={e => this.handleNameChange(e.target.value)} />
// ...
</form>
);
}
})
The idea is to keep the value of your fields in your local state. Then you can set the value of each of your fields to the value currently stored in your state, and attach an onChange handler that updates this value every the user types something. When you submit your form, all your values are available directly in your component's state.

Resources