I have a simple form in my render
function, like so:
render : function() { return ( <form> <input type="text" name="email" placeholder="Email" /> <input type="password" name="password" placeholder="Password" /> <button type="button" onClick={this.handleLogin}>Login</button> </form> ); }, handleLogin: function() { //How to access email and password here ? }
What should I write in my handleLogin: function() { ... }
to access Email
and Password
fields?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
There are a few ways to do this:
1) Get values from array of form elements by index
handleSubmit = (event) => { event.preventDefault(); console.log(event.target[0].value) }
2) Using name attribute in html
handleSubmit = (event) => { event.preventDefault(); console.log(event.target.elements.username.value) // from elements property console.log(event.target.username.value) // or directly } <input type="text" name="username"/>
3) Using refs
handleSubmit = (event) => { console.log(this.inputNode.value) } <input type="text" name="username" ref={node => (this.inputNode = node)}/>
Full example
class NameForm extends React.Component { handleSubmit = (event) => { event.preventDefault() console.log(event.target[0].value) console.log(event.target.elements.username.value) console.log(event.target.username.value) console.log(this.inputNode.value) } render() { return ( <form onSubmit={this.handleSubmit}> <label> Name: <input type="text" name="username" ref={node => (this.inputNode = node)} /> </label> <button type="submit">Submit</button> </form> ) } }
Method 2
Use the change
events on the inputs to update the component’s state and access it in handleLogin
:
handleEmailChange: function(e) { this.setState({email: e.target.value}); }, handlePasswordChange: function(e) { this.setState({password: e.target.value}); }, render : function() { return ( <form> <input type="text" name="email" placeholder="Email" value={this.state.email} onChange={this.handleEmailChange} /> <input type="password" name="password" placeholder="Password" value={this.state.password} onChange={this.handlePasswordChange}/> <button type="button" onClick={this.handleLogin}>Login</button> </form>); }, handleLogin: function() { console.log("EMail: " + this.state.email); console.log("Password: " + this.state.password); }
Working fiddle.
Also, read the docs, there is a whole section dedicated to form handling: Forms
Previously you could also use React’s two-way databinding helper mixin to achieve the same thing, but now it’s deprecated in favor of setting the value and change handler (as above):
var ExampleForm = React.createClass({ mixins: [React.addons.LinkedStateMixin], getInitialState: function() { return {email: '', password: ''}; }, handleLogin: function() { console.log("EMail: " + this.state.email); console.log("Password: " + this.state.password); }, render: function() { return ( <form> <input type="text" valueLink={this.linkState('email')} /> <input type="password" valueLink={this.linkState('password')} /> <button type="button" onClick={this.handleLogin}>Login</button> </form> ); } });
Documentation is here: Two-way Binding Helpers.
Method 3
Adding on to Michael Schock’s answer:
class MyForm extends React.Component { constructor() { super(); this.handleSubmit = this.handleSubmit.bind(this); } handleSubmit(event) { event.preventDefault(); const data = new FormData(event.target); console.log(data.get('email')); // reference by form input's `name` tag fetch('/api/form-submit-url', { method: 'POST', body: data, }); } render() { return ( <form onSubmit={this.handleSubmit}> <label htmlFor="username">Enter username</label> <input id="username" name="username" type="text" /> <label htmlFor="email">Enter your email</label> <input id="email" name="email" type="email" /> <label htmlFor="birthdate">Enter your birth date</label> <input id="birthdate" name="birthdate" type="text" /> <button>Send data!</button> </form> ); } }
See this Medium article: How to Handle Forms with Just React
This method gets form data only when Submit button is pressed. Much cleaner IMO!
Method 4
An alternative approach is to use the ref
attribute and reference the values with this.refs
. Here is a simple example:
render: function() { return (<form onSubmit={this.submitForm}> <input ref="theInput" /> </form>); }, submitForm: function(e) { e.preventDefault(); alert(React.findDOMNode(this.refs.theInput).value); }
More info can be found in the React docs:
https://facebook.github.io/react/docs/more-about-refs.html#the-ref-string-attribute
For a lot of the reasons described in How do I use radio buttons in React? this approach isn’t always the best, but it does present a useful alternative in some simple cases.
Method 5
For those who don’t want to use ref and reset the state with OnChange
event, you can just use simple OnSubmit handle and loop through the FormData
object.
Note that you cannot access formData.entries()
directly since it is an iterable, you have to loop over it.
This example is using React Hooks:
const LoginPage = () => { const handleSubmit = (event) => { const formData = new FormData(event.currentTarget); event.preventDefault(); for (let [key, value] of formData.entries()) { console.log(key, value); } }; return ( <div> <form onSubmit={handleSubmit}> <input type="text" name="username" placeholder="Email" /> <input type="password" name="password" placeholder="Password" /> <button type="submit">Login</button> </form> </div> ); };
And if you’re using TypeScript:
export const LoginPage: React.FC<{}> = () => { const handleSubmit: React.FormEventHandler<HTMLFormElement> = (event) => { const formData = new FormData(event.currentTarget); event.preventDefault(); for (let [key, value] of formData.entries()) { console.log(key, value); } }; return ( <div> <form onSubmit={handleSubmit}> <input type="text" name="username" placeholder="Email" /> <input type="password" name="password" placeholder="Password" /> <button type="submit">Login</button> </form> </div> ); };
Method 6
No need to use refs, you can access using event
function handleSubmit(e) { e.preventDefault() const {username, password } = e.target.elements console.log({username: username.value, password: password.value }) } <form onSubmit={handleSubmit}> <input type="text" id="username"/> <input type="text" id="password"/> <input type="submit" value="Login" /> </form>
Method 7
An easy way to deal with refs:
class UserInfo extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(e) {
e.preventDefault();
const formData = {};
for (const field in this.refs) {
formData[field] = this.refs[field].value;
}
console.log('-->', formData);
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input ref="phone" className="phone" type='tel' name="phone"/>
<input ref="email" className="email" type='tel' name="email"/>
<input type="submit" value="Submit"/>
</form>
</div>
);
}
}
export default UserInfo;
Method 8
You could switch the onClick
event handler on the button to an onSubmit
handler on the form:
render : function() { return ( <form onSubmit={this.handleLogin}> <input type="text" name="email" placeholder="Email" /> <input type="password" name="password" placeholder="Password" /> <button type="submit">Login</button> </form> ); },
Then you can make use of FormData
to parse the form (and construct a JSON object from its entries if you want).
handleLogin: function(e) { const formData = new FormData(e.target) const user = {} e.preventDefault() for (let entry of formData.entries()) { user[entry[0]] = entry[1] } // Do what you will with the user object here }
Method 9
If all your inputs / textarea have a name, then you can filter all from event.target:
onSubmit(event){ const fields = Array.prototype.slice.call(event.target) .filter(el => el.name) .reduce((form, el) => ({ ...form, [el.name]: el.value, }), {}) }
Totally uncontrolled form 😊 without onChange methods, value, defaultValue…
Method 10
I would suggest the following approach:
import {Autobind} from 'es-decorators'; export class Form extends Component { @Autobind handleChange(e) { this.setState({[e.target.name]: e.target.value}); } @Autobind add(e) { e.preventDefault(); this.collection.add(this.state); this.refs.form.reset(); } shouldComponentUpdate() { return false; } render() { return ( <form onSubmit={this.add} ref="form"> <input type="text" name="desination" onChange={this.handleChange}/> <input type="date" name="startDate" onChange={this.handleChange}/> <input type="date" name="endDate" onChange={this.handleChange}/> <textarea name="description" onChange={this.handleChange}/> <button type="submit">Add</button> </form> ) } }
Method 11
More clear example with es6 destructing
class Form extends Component { constructor(props) { super(props); this.state = { login: null, password: null, email: null } } onChange(e) { this.setState({ [e.target.name]: e.target.value }) } onSubmit(e) { e.preventDefault(); let login = this.state.login; let password = this.state.password; // etc } render() { return ( <form onSubmit={this.onSubmit.bind(this)}> <input type="text" name="login" onChange={this.onChange.bind(this)} /> <input type="password" name="password" onChange={this.onChange.bind(this)} /> <input type="email" name="email" onChange={this.onChange.bind(this)} /> <button type="submit">Sign Up</button> </form> ); } }
Method 12
Also, this can be used too.
handleChange: function(state,e) { this.setState({[state]: e.target.value}); }, render : function() { return ( <form> <input type="text" name="email" placeholder="Email" value={this.state.email} onChange={this.handleChange.bind(this, 'email')} /> <input type="password" name="password" placeholder="Password" value={this.state.password} onChange={this.handleChange.bind(this, 'password')}/> <button type="button" onClick={this.handleLogin}>Login</button> </form> ); }, handleLogin: function() { console.log("EMail: ", this.state.email); console.log("Password: ", this.state.password); }
Method 13
Give your inputs ref like this
<input type="text" name="email" placeholder="Email" ref="email" /> <input type="password" name="password" placeholder="Password" ref="password" />
then you can access it in your handleLogin like soo
handleLogin: function(e) { e.preventDefault(); console.log(this.refs.email.value) console.log(this.refs.password.value) }
Method 14
Here is shortest way to get data from form and the best way to avoid id and ref just by using FormData
import React, { Component } from 'react' class FormComponent extends Component { formSubmit = (event) => { event.preventDefault() var data = new FormData(event.target) let formObject = Object.fromEntries(data.entries()) console.log(formObject) } render() { return ( <div> <form onSubmit={this.formSubmit}> <label>Name</label> <input name="name" placeholder="name" /> <label>Email</label> <input type="email" name="email" /> <input type="submit" /> </form> </div> ) } } export default FormComponent
Method 15
If you are using Redux in your project you can consider using this higher order component https://github.com/erikras/redux-form.
Method 16
In many events in javascript, we have event
which give an object including what event happened and what are the values, etc…
That’s what we use with forms in ReactJs as well…
So in your code you set the state to the new value… something like this:
class UserInfo extends React.Component { constructor(props) { super(props); this.handleLogin = this.handleLogin.bind(this); } handleLogin(e) { e.preventDefault(); for (const field in this.refs) { this.setState({this.refs[field]: this.refs[field].value}); } } render() { return ( <div> <form onSubmit={this.handleLogin}> <input ref="email" type="text" name="email" placeholder="Email" /> <input ref="password" type="password" name="password" placeholder="Password" /> <button type="button">Login</button> </form> </div> ); } } export default UserInfo;
Also this is the form example in React v.16, just as reference for the form you creating in the future:
class NameForm extends React.Component { constructor(props) { super(props); this.state = {value: ''}; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); } handleChange(event) { this.setState({value: event.target.value}); } handleSubmit(event) { alert('A name was submitted: ' + this.state.value); event.preventDefault(); } render() { return ( <form onSubmit={this.handleSubmit}> <label> Name: <input type="text" value={this.state.value} onChange={this.handleChange} /> </label> <input type="submit" value="Submit" /> </form> ); } }
Method 17
I use like this using React Component state:
<input type="text" name='value' value={this.state.value} onChange={(e) => this.handleChange(e)} /> handleChange(e){ this.setState({[e.target.name]: e.target.value}) }`
Method 18
onChange(event){ console.log(event.target.value); } handleSubmit(event){ event.preventDefault(); const formData = {}; for (const data in this.refs) { formData[data] = this.refs[data].value; } console.log(formData); } <form onSubmit={this.handleSubmit.bind(this)}> <input type="text" ref="username" onChange={this.onChange} className="form-control"/> <input type="text" ref="password" onChange={this.onChange} className="form-control"/> <button type="submit" className="btn-danger btn-sm">Search</button> </form>
Method 19
This might help Meteor (v1.3) users:
render: function() { return ( <form onSubmit={this.submitForm.bind(this)}> <input type="text" ref="email" placeholder="Email" /> <input type="password" ref="password" placeholder="Password" /> <button type="submit">Login</button> </form> ); }, submitForm: function(e) { e.preventDefault(); console.log( this.refs.email.value ); console.log( this.refs.password.value ); }
Method 20
To improve the user experience; when the user clicks on the submit button, you can try to get the form to first show a sending message. Once we’ve received a response from the server, it can update the message accordingly. We achieve this in React by chaining statuses. See codepen or snippets below:
The following method makes the first state change:
handleSubmit(e) { e.preventDefault(); this.setState({ message: 'Sending...' }, this.sendFormData); }
As soon as React shows the above Sending message on screen, it will call the method that will send the form data to the server: this.sendFormData(). For simplicity I’ve added a setTimeout to mimic this.
sendFormData() { var formData = { Title: this.refs.Title.value, Author: this.refs.Author.value, Genre: this.refs.Genre.value, YearReleased: this.refs.YearReleased.value}; setTimeout(() => { console.log(formData); this.setState({ message: 'data sent!' }); }, 3000); }
In React, the method this.setState() renders a component with new properties. So you can also add some logic in render() method of the form component that will behave differently depending on the type of response we get from the server. For instance:
render() { if (this.state.responseType) { var classString = 'alert alert-' + this.state.type; var status = <div id="status" className={classString} ref="status"> {this.state.message} </div>; } return ( ...
Method 21
If you have multiple occurrences of an element name, then you have to use forEach().
html
<input type="checkbox" name="delete" id="flizzit" /> <input type="checkbox" name="delete" id="floo" /> <input type="checkbox" name="delete" id="flum" /> <input type="submit" value="Save" onClick={evt => saveAction(evt)}></input>
js
const submitAction = (evt) => { evt.preventDefault(); const dels = evt.target.parentElement.delete; const deleted = []; dels.forEach((d) => { if (d.checked) deleted.push(d.id); }); window.alert(deleted.length); };
Note the dels in this case is a RadioNodeList, not an array, and is not an Iterable. The forEach()is a built-in method of the list class. You will not be able to use a map() or reduce() here.
Method 22
This is an example of dynamically added field. Here form data will store by input name key using React useState hook.
import React, { useState } from 'react'
function AuthForm({ firebase }) {
const [formData, setFormData] = useState({});
// On Form Submit
const onFormSubmit = (event) => {
event.preventDefault();
console.log('data', formData)
// Submit here
};
// get Data
const getData = (key) => {
return formData.hasOwnProperty(key) ? formData[key] : '';
};
// Set data
const setData = (key, value) => {
return setFormData({ ...formData, [key]: value });
};
console.log('firebase', firebase)
return (
<div className="wpcwv-authPage">
<form onSubmit={onFormSubmit} className="wpcwv-authForm">
<input name="name" type="text" className="wpcwv-input" placeholder="Your Name" value={getData('name')} onChange={(e) => setData('name', e.target.value)} />
<input name="email" type="email" className="wpcwv-input" placeholder="Your Email" value={getData('email')} onChange={(e) => setData('email', e.target.value)} />
<button type="submit" className="wpcwv-button wpcwv-buttonPrimary">Submit</button>
</form>
</div>
)
}
export default AuthForm
Method 23
<form onSubmit={handleLogin}> <input type="text" name="email" placeholder="Email" /> <input type="text" name="password" placeholder="Password" /> <button type="submit">Login</button> </form> const handleLogin = (event) => { event.preventDefault(); console.log(event.target[0].value) console.log(event.target[1].value) }
Method 24
I think this is also the answer that you need. In addition, Here I add the required attributes. onChange attributes of Each input components are functions. You need to add your own logic there.
handleEmailChange: function(e) { this.setState({email: e.target.value}); }, handlePasswordChange: function(e) { this.setState({password: e.target.value}); }, formSubmit : async function(e) { e.preventDefault(); // Form submit Logic }, render : function() { return ( <form onSubmit={(e) => this.formSubmit(e)}> <input type="text" name="email" placeholder="Email" value={this.state.email} onChange={this.handleEmailChange} required /> <input type="password" name="password" placeholder="Password" value={this.state.password} onChange={this.handlePasswordChange} required /> <button type="button">Login</button> </form>); }, handleLogin: function() { //Login Function }
Method 25
This will be an easiest method
const formValidator = (form) => { let returnData = {} console.log(form.length); for (let i = 0; i < form.length; i++) { const data = form[i] if (data.name != null && data.name != "") { returnData[data.name] = data.value; } } return returnData }
In form simply
<form onSubmit={(e) => { e.preventDefault() let data = formValidator(e.currentTarget) }}> <RoundTextFiled name='app-id' style={{ marginTop: '10px', borderRadius: '20px' }} label="App id" fullWidth required /> <RoundTextFiled name='api-hash' style={{ marginTop: '5px' }} label="Api hash" fullWidth required /> <RoundTextFiled name='channel-id' style={{ marginTop: '5px' }} label="Channel id" fullWidth required /> <Button type='submit' variant="contained" fullWidth style={{ padding: '10px', marginTop: '5px', borderRadius: '10px' }}>Login</Button> </form>
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0