I am new to react and redux technology. now started building an application that contains several redux forms. We want to submit simple form with values.
For ex: login form
Username : text input field
Password: text input field
Submit button
After entering values in fields and click on submit button i want to get the username and password field values in object or json data .. so that I can store it to my server with POST method.
Right now we are using handleSubmit(), but data is not coming as object
1 - The best practice to deal with input values are making them controlled. Which means :
Instead of
<input type='password' />
You do :
<input
type='password'
value={password}
onChange={ event => myInputHandler( event.target.value ) }
/>
The value might come from your state, redux state or as a props etc.
Your handler function differs according to where you store it.
I will give you an example with react state :
<input
type='password'
value={this.state.password}
onChange={ event => this.setState({ password : event.target.value }) }
/>
So whenever someone types, your onChange handler will be called, so that your react state will update with the input ( event.target.value ).
2 - If you need these values when a user submits, then you need to wrap these input fields within a form element and attach a onSubmit handler.
onSubmitHandler( event ){
event.preventDefault()
let password = this.state.password
// use password or other input fields, send to server etc.
}
<form onSubmit={ event => this.onSubmitHandler(event) }>
<input
type='password'
value={this.state.password}
onChange={ event => this.setState({ password : event.target.value }) }
/>
</form>
Hope you get what you need.
If you are using redux to store state then use redux-from then use redux from
import React from 'react'
import {Field, reduxForm} from 'redux-form'
const SimpleForm = props => {
const {handleSubmit, submitting} = props return (
<form onSubmit={handleSubmit(e=>console.log('your form detail here', e))}>
<div>
<label>First Name</label>
<div>
<Field name="firstName" component="input" type="text" placeholder="First Name" />
</div>
</div>
<div>
<label>Last Name</label>
<div>
<Field name="lastName" component="input" type="text" placeholder="Last Name" />
</div>
</div>
<div>
<button type="submit" disabled={pristine || submitting}>Submit</button>
</div>
</form>
) }
export default reduxForm({ form: 'simple'})(SimpleForm)
Go here for more detail
https://redux-form.com
I put the name of the input as the key that I want to use.
Then each time the input changes I destructure the event passed to the onChange function, and I use the name,value to update the state.
On form submit make sure to use preventDefault(); in order to avoid the page refreshing.
import React, { Component } from 'react'
class FormExample extends Component {
constructor(props){
super(props)
this.state = {
formData: {}
}
}
handleInputChange = ({ target: { name,value } }) => {
this.setState({
formData: {
...this.state.formData,
[name]: value
}
})
}
handleFormSubmit = e => {
e.preventDefault()
// This is your object
console.log(this.state.formData)
}
render() {
return(
<div>
<Form
handleSubmit={this.handleFormSubmit}
handleChange={this.handleInputChange}
/>
</div>
)
}
}
const Form = ({ handleSubmit, handleChange }) => (
<form onSubmit={handleSubmit}>
<input onChange={handleChange} name="username" type="text" placeholder="Username" />
<input onChange={handleChange} name="password" type="password" placeholder="Password" />
<button>Submit</button>
</form>
)
export default FormExample
Related
I am trying on trial and error basis. I tried to insert username and password in the database using reactjs by event handling, but whenever I enter the username and the password both fields get the same value. For example, if I put 'ABC' as username and 123 as password then the username and password will get same value 123 in the database.
1.trying to insert data using event handling.
class Login extends Component{
ref = firebase.firestore().collection('login');
state = {
username: '',
password: ''
};
handleChange = (event) => {
const state = this.state
state.username = event.target.value;
state.password=event.target.value;
//console.log(state[event.target.username]);
//console.log(state[event.target.password]);
this.setState({username:state.username,
password:state.password });
console.log(state.username);
console.log(state.password);
}
onSubmit = (event) => {
event.preventDefault();
const { username,password } = this.state;
this.ref.add({
username,
password
}).then((docRef) => {
this.setState({
username: '',
password:''
});
this.props.history.push("/")
})
.catch((error) => {
console.error("Error adding document: ", error);
});
}
render()
{
return(
<form onSubmit={this.onSubmit}>
<div className="container mt-5 w-50">
<div className="form-group">
<label for= "user name" className="">User Name:</label>
<input type="text" name="userName" placeholder="UserName" className="form-control w-50" onChange={this.handleChange.bind(this)}/><br/>
<label for="password" className="">Password:</label>
<input type="password" name="password" placeholder="password" className="form-control w-50" onChange={this.handleChange.bind(this)}/><br/>
<button name="Login" className="btn btn-success w-50 mb-3">Login</button><br/>
{/* Don't Have an Account? SignUp */}
<Link to="/signup">Don't Have an Account? SignUp</Link>
</div>
</div>
</form>
);
}
}
export default Login;
username and password should get their actual values.
I believe this is because you are setting the state of both to the same value (event.target.value) in your event handler. You're also mutating state which is not a good thing to do in any situation.
in your handleChange function you are changing username AND password state values to the value of event.target.value which will happen when onChange fires in whichever input you are using handleChange as a listener.
change your handleChange function to this:
handleChange = event => {
let {name, value} = event.target;
this.setState({
[name]: value
});
}
by using {[name]: value} when the event fires in an input with name="password" the password value in your component's state will update
Your render function is a bit confusing but I am going to assume you're rendering a form with labels for username and password...
then in your input within your form (which I can't see in your markdown above, but I'm assuming is in the Login component):
<input name="username" value={this.state.username} onChange={this.handleChange} />
<input name="password" value={this.state.password} onChange={this.handleChange} />
I have a multi steps form in which i have used a Formik and Yup libraries.
But the validation that i am using of yup library is not working at all. In React debugger tool i am getting it's value as empty. So, whatever i write in the input field it validates with "Required" message as it's value is empty.
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
let accountInfoSchema = Yup.object().shape({
name: Yup.string()
.max(20, 'Too Long!')
.required('Name is Required'),
});
class AccountInfo extends Component {
handleChange = event => {
this.setState({
userAccountData: Object.assign(
{},
this.state.userAccountData,
{ [event.target.name]: event.target.value }
),
})
}
AccountInfoView = () => {
return (
<section className="form">
<React.Fragment>
<Formik
initialValues={{name:'' }}
validationSchema={accountInfoSchema}
render={() => {
return(
<Form onSubmit={this.handleSubmit}>
{this.Step1()}
{this.Step2()}
{this.Step3()}
<li className="stb_btn half">
<div className="custom_group">
{this.previousButton()}
</div>
</li>
<li className="stb_btn half">
<div className="custom_group">
{this.nextButton()}
</div>
</li>
</Form>
);
}}
/>
</React.Fragment>
</div>
</section>
)
}
Step1 = () => {
return(
<li>
<div className="custom_group">
<Field type="text" name="name" className="trans text_input" placeholder="Enter your name" value={this.state.userAccountData['name']} onChange={this.handleChange} />
<label className="label_two">Name</label>
<ErrorMessage name="name" />
</div>
</li>
)
}
render() {
return (
<div>{this.AccountInfoView()}</div>
)
}
}
please review the react console response for the value as empty.
The reason why it isn't validating is because you are passing to the Field this.state.userAccountData['name'] and onChange={this.handleChange}.
Formik already have a state to store all of the data from your form, you don't need to keep it in the components state.
When you add onChange={this.handleChange} to the field, you change the component's state, but don't change the Formik's state, this is why the validation isn't triggering.
I'm not sure why you are keeping the name in the state, but if you don't have any reason why these are unecessary.
// formik already handle the state for you inside `values`
handleChange = event => {
this.setState({
userAccountData: Object.assign(
{},
this.state.userAccountData,
{ [event.target.name]: event.target.value }
),
})
}
// Formik already handles the value and the onChange of the input
<Field type="text" name="name" className="trans text_input" placeholder="Enter your name" value={this.state.userAccountData['name']} onChange={this.handleChange} />
The only thing you need is to set the field's name prop, so it matches the validation.
// this is enough
<Field type="text" name="name" className="trans text_input" placeholder="Enter your name" />
I have an "edit category" component in my React application.
The ID is passed through the URL.
When the component is mounted, the action "fetchCategory" is called, which updates the props on the component with the current category.
I have a form which I want to be pre-populated, which I'm currently doing using the defaultValue on the input.
However, this isn't reflected on the state and the label for the text field overlaps the input field.
Any help would be greatly appreciated. I'll leave snippets of my code below which could help with understanding what I'm trying to do.
import React, { Component } from "react";
import { connect } from "react-redux";
import { fetchCategory } from "../../store/actions/categoryActions";
class AddOrEditCategory extends Component {
componentDidMount() {
this.props.fetchCategory(this.props.match.params.id);
if (this.props.match.params.id) {
this.setState({
_id: this.props.match.params.id
});
}
}
handleSubmit = e => {
e.preventDefault();
console.log(this.state);
};
handleChange = e => {
this.setState({
[e.target.id]: e.target.value
});
};
render() {
const addingNew = this.props.match.params.id === undefined;
return (
<div className="container">
<h4>{addingNew ? "Add category" : "Edit category"}</h4>
<form onSubmit={this.handleSubmit}>
<div className="input-field">
<input
type="text"
id="name"
defaultValue={this.props.category.name}
onChange={this.handleChange}
/>
<label htmlFor="name">Category name</label>
</div>
<div className="input-field">
<input
type="text"
id="urlKey"
onChange={this.handleChange}
defaultValue={this.props.category.urlKey}
/>
<label htmlFor="urlKey">URL Key</label>
</div>
<button className="btn">{addingNew ? "Add" : "Save"}</button>
</form>
</div>
);
}
}
const mapStateToProps = state => {
return {
category: state.categoryReducer.category
};
};
export default connect(
mapStateToProps,
{ fetchCategory }
)(AddOrEditCategory);
EDIT: Included whole component as requested
You need to replace the 'defaultValue' attribute with 'value' in the inputs.
You are using a controlled vs uncontrolled component. You dont need to use defaultValue.
You can set the initial values on the promise success for fetchCategory
componentDidMount() {
this.props.fetchCategory(this.props.match.params.id).then(response => {
// Set the initial state here
}
}
OR in
componentWillReceiveProps(nextProps) {
// Compare current props with next props to see if there is a change
// in category data received from action fetchCategory and set the initial state
}
React docs
<form onSubmit={this.handleSubmit}>
<div className="input-field">
<input
type="text"
id="name"
onChange={this.handleChange}
value={this.state.name} //<---
/>
<label htmlFor="name">Category name</label>
</div>
<div className="input-field">
<input
type="text"
id="urlKey"
onChange={this.handleChange}
value={this.state.urlKey}
/>
<label htmlFor="urlKey">URL Key</label>
</div>
<button className="btn">{addingNew ? "Add" : "Save"}</button>
</form>
Please help me to understand where I am doing what mistake? I created CustomerForm React Component, which having few form fields. These form fields will add records and in another component will show records into table format.
Every thing is working fine for CustomerForm React Component, but if I am adding onSubmit function than form fields are not loading and I am getting console error as:-
Uncaught ReferenceError: onSubmit is not defined
at new CustomerForm (index.js:32590)
<button type="submit" className="btn btn-primary" onClick={ e => this.onSubmit(e)} > Submit </button>
Also please suggest any better way to write ReactJS code using Props & State...
// Let's import react for creating component
import React from "react";
// Create CustomerForm component
class CustomerForm extends React.Component{
// create constructor function for CustomerForm component
constructor(props){
// call super, so constructor function can connect with CustomerForm component
super(props);
// Use state add object with their property and value
this.state = {
firstName : "",
lastName : "",
phoneNo : "",
issue : "",
}
// Create changeData function
// changeData = e => {
// this.setState({
// [e.target.name] : e.target.value
// });
// };
onSubmit = e => {
e.preventDefault();
console.log(this.state);
}
} // close constructor function
render(){
return(
<form>
<div className="form-group">
<label htmlFor="fname">First name</label>
<input
type="text"
className="form-control"
id="fname"
placeholder="First name"
value={this.state.firstName}
onChange={e => this.setState({ firstName: e.target.value })}
/>
{/* call setState for change firstName value
question - I created changeData function which target name attribute and change value for form fields, but it's not working
onChange={e => this.changeData(e)}
*/}
</div>
<div className="form-group">
<label htmlFor="lname">Last name</label>
<input
type="text"
className="form-control"
id="lname"
placeholder="Last name"
value={this.state.lastName}
onChange={e => this.setState({ lastName: e.target.value })}
/>
{/* call setState for change lastName value */}
</div>
<div className="form-group">
<label htmlFor="phone">Phone no.</label>
<input
type="text"
className="form-control"
id="phone"
placeholder="Phone no."
value={this.state.phoneNo}
onChange={e => this.setState({phoneNo: e.target.value})}
/>
{/* call setState for change phoneNo value */}
</div>
<div className="form-group">
<label htmlFor="issue">Issue</label>
<textarea
className="form-control"
id="issue"
rows="3"
value={this.state.issue}
onChange={e => this.setState({issue: e.target.value})}
>
{/* call setState for change issue value */}
</textarea>
</div>
<button
type="submit"
className="btn btn-primary"
onClick={ e => this.onSubmit(e)}
>
Submit
</button>
</form>
);
}
}
export default CustomerForm;
You're declaring a variable named onSubmit on the constructor and trying to access it with this.onSubmit, like a property.
You can do this in your constructor:
this.onSubmit = e => {
e.preventDefault();
console.log(this.state);
}
The suggestion
A better way to accomplish this is extracting your onSubmit method to a class method, with makes your code more readable and more consistent. Would be something like this:
// Let's import react for creating component
import React from "react";
// Create CustomerForm component
class CustomerForm extends React.Component{
// create constructor function for CustomerForm component
constructor(props){
// call super, so constructor function can connect with CustomerForm component
super(props);
// Use state add object with their property and value
this.state = {
firstName : "",
lastName : "",
phoneNo : "",
issue : "",
}
}
/////////
/// Your submit handler is now a method in the CustomerForm class,
/// so you can access with the keyword "this"
onSubmit(e) {
e.preventDefault();
console.log(this.state);
}
render(){
return(
<form onSubmit={e => this.onSubmit(e)}>
{/* Note that I've changed your handler to form,
is usually better than put on a button, since you're using a form already */}
<div className="form-group">
<label htmlFor="fname">First name</label>
<input
type="text"
className="form-control"
id="fname"
placeholder="First name"
value={this.state.firstName}
onChange={e => this.setState({ firstName: e.target.value })}
/>
{/* call setState for change firstName value
question - I created changeData function which target name attribute and change value for form fields, but it's not working
onChange={e => this.changeData(e)}
*/}
</div>
<div className="form-group">
<label htmlFor="lname">Last name</label>
<input
type="text"
className="form-control"
id="lname"
placeholder="Last name"
value={this.state.lastName}
onChange={e => this.setState({ lastName: e.target.value })}
/>
{/* call setState for change lastName value */}
</div>
<div className="form-group">
<label htmlFor="phone">Phone no.</label>
<input
type="text"
className="form-control"
id="phone"
placeholder="Phone no."
value={this.state.phoneNo}
onChange={e => this.setState({phoneNo: e.target.value})}
/>
{/* call setState for change phoneNo value */}
</div>
<div className="form-group">
<label htmlFor="issue">Issue</label>
<textarea
className="form-control"
id="issue"
rows="3"
value={this.state.issue}
onChange={e => this.setState({issue: e.target.value})}
>
{/* call setState for change issue value */}
</textarea>
</div>
<button
type="submit"
className="btn btn-primary"
>
Submit
</button>
</form>
);
}
}
export default CustomerForm;
Controlled Components
Just one more thing I think it may be helpful to you (I've noted your comment about changeData) so if you not resolve the way to do controlled inputs, this minimalist example may help you, with a onChangeHandler I usually use:
import React from 'react';
export default class MyControlledComponent extends React.Component {
constructor(props){
super(props);
// Initiating the first value for our controlled component
this.state = {
name: ""
}
}
submitHandler(e) {
e.preventDefault();
console.log('Hi, ' + this.state.name + '!');
}
onChangeHandler(e) {
const { name, value } = e.target
/*
Here we using the name property of your input to
increase reuse of this function
*/
this.setState({
[name]: value
});
}
render(){
return (
<div className="my-app">
<form onSubmit={e => this.submitHandler(e)}>
<input type="text"
name="name"
value={this.state.name}
onChange={e => this.onChangeHandler(e)} />
<button>Send!</button>
</form>
</div>
)
}
}
Hope it helps!
Your onSubmit function is not bind either bind it in constructor or use fat arrow properly like
{(return)=>{functionname()}}
How to provide validations for react js form.
I have taken form with two fields. if two fields are enabled then only need to enable save button.
import React from 'react'
import { Button, Checkbox, Form } from 'semantic-ui-react'
const FormExampleForm = () => (
<Form>
<Form.Field>
<label>First Name</label>
<input placeholder='First Name' />
</Form.Field>
<Form.Field>
<label>Last Name</label>
<input placeholder='Last Name' />
</Form.Field>
<Form.Field>
<Checkbox label='I agree to the Terms and Conditions' />
</Form.Field>
<Button type='submit'>Submit</Button>
</Form>
)
export default FormExampleForm
In redux forms 6.7 there's a simple property called pristine which can be used to do this. But if the user enters some value in at least one input field the submit button gets activated. To achieve that you may need to do something like this.
render() {
// const { handleSubmit } = this.props;
const {handleSubmit, pristine, reset, submitting} = this.props
return (
<form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<div>
<label>First Name</label>
<div>
<Field name="firstName" component="input" type="text" placeholder="First Name"/>
</div>
</div>
<button type="submit" className="btn btn-primary" disabled={pristine || submitting}>Submit</button>
</form>
);
}
}
But if you need to enable submit button, say when the user inputs values in 2 given fields or so, then this becomes complex. You need to do something like this. Here's my sample usecase. The form has 3 fields firstName, lastName and age. The submit button gets activated only if the user enters values for firstName and lastName input fields here. Please check out the following code.
import React, { Component } from 'react';
import { Field, reduxForm, formValueSelector } from 'redux-form';
import { connect } from 'react-redux';
class UserNew extends Component {
constructor(props) {
super(props);
this.isSubmitEnabled = this.isSubmitEnabled.bind(this);
}
onSubmit(values) {
console.log(values);
}
isSubmitEnabled() {
// Access field values here and validate them
const firstName = this.props.firstNameValue;
const lastName = this.props.lastNameValue;
if(firstName && lastName){
return true;
}
return false;
}
render() {
const { handleSubmit } = this.props;
const isEnabled = this.isSubmitEnabled();
return (
<form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<div>
<label>First Name</label>
<div>
<Field name="firstName" component="input" type="text" />
</div>
</div>
<div>
<label>Last Name</label>
<div>
<Field name="lastName" component="input" type="text" />
</div>
</div>
<div>
<label>Age</label>
<div>
<Field name="age" component="input" type="text" />
</div>
</div>
<button type="submit" className="btn btn-primary" disabled={!isEnabled}>Submit</button>
</form>
);
}
}
UserNew = reduxForm({
form: 'UserNewForm'
})(
UserNew
);
// Decorate with connect to read form values
const selector = formValueSelector('UserNewForm') // <-- same as form name
UserNew = connect(state => {
const firstNameValue = selector(state, 'firstName')
const lastNameValue = selector(state, 'lastName')
return {
firstNameValue,
lastNameValue,
}
})(UserNew)
export default UserNew;
To access field values you need to use formValueSelector in ReduxForms. For that you need to connect your form to redux store using connect helper.
Hope this helps. Happy coding !
Either you can use Redux-form as its not used in above code, so you can write custom JS validation code. For this you need to follow below
Initialise state in
contructor(){
this.state{
first_name: null,
last_name: null,
}
}
Change state of every input element onChange onChange={()=>this.setState({first_name: event.target.value})}
Now add onClick property to <Button onClick={this.handleSubmit} />
inside handleSubmit() you can get values through local state of component and add validation rules like
if(this.state.first_name =="") {
console.log("Enter first name")
}