I'm creating my first Redux-form but the form doesn't add the info to database.
class UserInfo extends Component{
renderField(field) {
const { meta: { touched, error } } = field;
const className = `form-group ${touched && error ? "has-danger" : ""}`;
return (
<div className={className}>
<label>{field.label}</label>
<input className="form-control" type="text" {...field.input} />
<div className="text-help">
{touched ? error : ""}
</div>
</div>
);
}
onSubmit(values){
//this.props.addUser(values);
console.log(values);
}
render(){
const { handleSubmit, pristine, reset, submitting } = this.props;
return(
<div>
<div>
<form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<div className='form-row'>
<Field label='Name' component={this.renderField} name='username' />
<Field label='Address' component={this.renderField }name='address' />
<Field label='Contact' component={this.renderField} name='contact' />
<Field label='Email'component={this.renderField} name='email' />
<button type="submit" className="btn btn-primary">Add new User</button>
</div>
</form>
</div>
</div>
);
}
}
function validate(values) {
const errors = {};
if (!values.uername) {
errors.username = 'Please enter a first name';
}
if (!values.address) {
errors.address = 'Please enter an address';
}
if (!values.contact) {
errors.contact = 'Please enter a phone number'
}
if (!values.email) {
errors.email = 'Please enter an email';
}
return errors;
}
export default reduxForm({
validate,
form: 'UserForm'
})(connect(null, { addUser })(UserInfo));
If I use console.log(values) in onSubmit function I don't get any output in the browser.I'm using createLogger to help with actions. And it shows type:
"##redux-form/SET_SUBMIT_FAILED"
I can't figure out what type of error this is.
Use developer tools(ctrl+shift+I), take redux-- state--form--'NameofReduxform'--syncErrors. Then, you might see some required fields.. You need to fill the fields to make the submit work. Hope this helps!
Related
I am using formik in react js.. currently I just added enableReinitialize to update the initialValues after there is any change in state.. so here the validation message are shown even after the correcting the text. This validation message get's removed after clicking outside of textbox. can I hide this message as soon as the the data is corrected in textbox.
Dirty and isValid keeps the button disabled even though there are no validations.
Register.JS
import React, { Component, useState } from 'react';
import {Formik} from 'formik';
import validateSignUp from '../../containers/Validations/SignUp/SignUpValidation'
class Register extends Component {
constructor(props) {
super();
this.state = {
fields: {CountryCode:'', EmailId:'', Password:''},
errors: {},
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
let fields = this.state.fields;
fields[e.target.name] = e.target.value;
this.setState({
fields,
});
}
handleSubmit(){
console.log(this.state.fields);
}
render() {
return (
<Formik
enableReinitialize
initialValues={this.state.fields}
validate={validateSignUp}
>
{({errors, touched, handleBlur, isSubmitting, isValid, dirty}) => (
<div className='signUp-form form_wrapper'>
<div className='form-body'>
<form name='first' onSubmit={this.handleSubmit}>
<div className='row'></div>
<div className='form-group'>
<label>Email address</label>
<input type='email' name="EmailId"
onChange={this.handleChange} placeholder='abc#example.com'
onBlur={handleBlur} value={this.state.fields.EmailId}
className='form-control'/>
<div className='info-message'>
<div className='errorMsg'>{errors.EmailId &&
touched.EmailId && errors.EmailId}</div>
</div>
</div>
<div className='form-group'>
<label>Password</label>
<input type='password' name="Password"
onChange={this.handleChange} onBlur={handleBlur} value={this.state.fields.Password}
className='form-control'/>
<div className='info-message'>
<div className='errorMsg'>{errors.Password &&
touched.Password && errors.Password}</div>
</div>
</div>
<button type='submit' disabled={!(isValid && dirty)} className='btn btn-danger'>
continue
</button>
</form>
</div>
</div>
)}
</Formik>
);
}
}
export default Register;
SignUpValidation.JS
const validateSignUp = validate => {
const errors = {};
if (!validate.EmailId) {
errors.EmailId = 'Please Enter Email ID';
} else if (!/^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(validate.EmailId)) {
errors.EmailId = 'Invalid email address';
}
if (!validate.Password) {
errors.Password = 'Please Enter New Password Which you want to set';
} else if (!validate.Password.match(/^.*(?=.{8,})(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*
[##$%&]).*$/)) {
errors.Password = 'Password Must contain at least one number and one uppercase and lowercase
letter, and at least 8 or more characters';
}
return errors;
};
export default validateSignUp;
I think you should use yup for formik validations as it automatically handle those cases.
I have redux form in a class component and for some reason when I console log the formValues I am getting undefined what is the problem?
class CreateTeamBox extends Component{
handleFormSubmit({name}){
console.log(name);
}
renderError = ({ touched, error}) => {
if(touched && error) {
return(
<div>{error}</div>
);
}
}
renderInput = ({input, label, type, meta}) => {
return(
<div className={styles.formGroup}>
<label>{label}</label>
<input {...input} />
<div className={styles.errorWrapper}>
{this.renderError(meta)}
</div>
</div>
);
}
render() {
const {handleSubmit, error} = this.props ;
return(
<div className={styles.createTeamBox}>
<div className={styles.titleWrapper}>
<h2>create team</h2>
</div>
<div className={styles.bodyWrapper}>
<div className={styles.submitErrorWrapper}>
{error ? <Error error={error} /> : null}
</div>
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
<Field name="name" component={this.renderInput} label="name" />
<button className={styles.button} type="submit" >create</button>
</form>
</div>
</div>
)
}
}
const validate = (formValues) => {
console.log(formValues.name);
const name = formValues.name;
const errors = validateForm(name);
return errors;
}
export default reduxForm({
form: 'createTeamForm',
validate
})(CreateTeamBox);
I have other reduxform in the same given project with different names, is it causing the problem? Im not sure why it is happening as I havecopied most of the coe from working reduxform in the given project .
the default value of formValues will be empty object, after enter some data to the field then you can get the value, or you can pass the value by using initialValues
I am trying to get the values from my second form. It renders some select options and when I hit the delete button it just returns an empty object. How do I get the value from the options. With the normal input fields it would pass values with the name.
For example if I had an input type="text" name="email", when I would submit this it would give my an object like:
{email: "some string"}
Here is the code:
import React , { Component } from 'react';
// import * as actions from '../actions';
import { reduxForm, Field } from 'redux-form';
import {connect} from 'react-redux';
import {postBooks, deleteBook} from '../../actions/booksActions';
class BooksForm extends Component {
renderField(field) {
const { meta: {touched, error} } = field;
const className = `form-group ${touched && error ? 'has-danger' : ''}`;
return (
<div className={className}>
<label className="control-label"><strong>{field.label}:</strong></label>
<input
className="form-control"
type={field.type}
{...field.input}
/>
<div className="text-help">
{ touched ? error : ''}
</div>
</div>
);
}
renderSelectField(field) {
const bookList = _.map(field.options, (book) => {
return (
<option key={book._id}>{book.title}</option>
)
});
return(
<div className="form-group">
<label htmlFor="sel1" className="control-label">{field.label}</label>
<select className="form-control" id="sel1">
{bookList}
</select>
</div>
);
}
onSubmit(values) {
this.props.postBooks(values);
}
onDelete(values) {
console.log(values);
}
render() {
const {handleSubmit} = this.props;
return (
<div>
<div className="well">
<form className="panel" onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<div className="panel-body">
<Field
label="Title"
name="title"
type="text"
component={this.renderField}
/>
<Field
label="Description"
name="description"
type="text"
component={this.renderField}
/>
<Field
label="Price"
name="price"
type="text"
component={this.renderField}
/>
<button className="btn btn-primary">Save Book</button>
</div>
</form>
</div>
<form className="Panel" onSubmit={handleSubmit(this.onDelete.bind(this))}>
<div className="panel-body">
<Field
label="Select Book"
name="selectedBook"
options={this.props.books}
component={this.renderSelectField}
/>
<button className="btn btn-danger">Delete</button>
</div>
</form>
</div>
);
}
}
function validate(values) {
const errors = {};
return errors;
}
function mapStateToProps(state) {
return {
books: state.books
}
}
export default reduxForm({
validate,
form: 'bookForm'
})(connect(mapStateToProps, {postBooks, deleteBook})(BooksForm));
In renderSelectField I needed to add {...field.input} into the select to allow redux-form to monitor it.
<select className="form-control" id="sel1" {...field.input}>
i am trying to load the initial value in from but couldn't do this, i am using redux-from, i set the profile data in redux store and can access the data through the props(console them) but can't able to show in the form input. i am trying to replicate this redux-from example. but couldn' able to continue it.
below is the code.
import React from 'react';
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import { required, email, maxLength25 } from '../utils/validations';
import { renderField,
renderSelectField,
renderRadioField,
renderTextAreaField,
renderCheckboxField
} from '../utils/textFieldGroup';
import countries from '../utils/countryList';
import { profileUpdate, profile } from '../actions/user';
const validateAndUpdateRecords = (values, dispatch) => {
return dispatch(profileUpdate(values))
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
})
}
class ProfileForm extends React.Component {
componentWillMount(dispatch){
console.log('mount');
this.props.fetchProfile();
}
render(){
const { handleSubmit, submitSucceeded, error, profile } = this.props
console.log('prof',profile);
return (
<div>
<h1>Profile Page</h1>
<form onSubmit={handleSubmit(validateAndUpdateRecords)}>
<div className={typeof error!='undefined'?'show alert alert-danger': 'hidden'}>
<strong>Error!</strong> {error}
</div>
<Field name="fname" type="text" component={renderField} label="First Name"
validate={[ required, maxLength25 ]}
/>
<Field name="lname" type="text" component={renderField} label="Last Name"
validate={[ required, maxLength25 ]}
/>
<Field component={renderRadioField} name="gender" label="Gender" options={[
{ title: 'Male', value: 'male' },
{ title: 'Female', value: 'female' }
]} validate={ required } />
<Field name="country" type="text" data={countries} component={renderSelectField} label="Country"
validate={[ required ]}
/>
<Field name="about_us" type="text" component={renderTextAreaField} label="About Us"
validate={[ required ]}
/>
<Field name="newsletter" type="checkbox" component={renderCheckboxField} label="Newsletter"
validate={[ required ]}
/>
<p>
<button type="submit" disabled={submitSucceeded} className="btn btn-primary btn-lg">Submit</button>
</p>
</form>
</div>
)
}
}
ProfileForm = reduxForm({
form:'profile'
})(ProfileForm)
ProfileForm = connect(
state => ({
initialValues: state.user.profile
})
)(ProfileForm)
export default ProfileForm;
//text field
export const renderField = ({ input, label, type, meta: { touched, error, warning } }) => (
<div className={classnames('form-group', { 'has-error':touched && error })}>
<label className="control-label">{label}</label>
<div>
<input {...input} placeholder={label} type={type} className="form-control"/>
{touched && ((error && <span className="help-block">{error}</span>))}
</div>
</div>
)
Thanks in advance
Finally i figure out the solutions. below is the solutions. We need to add enableReinitialize : true as mentioned below. If our initialValues prop gets updated, form will update too.
ProfileForm = reduxForm({
form:'profile',
enableReinitialize : true
})(ProfileForm)
I have a form in a modal using redux-form. I have several text fields, but you can not type in them. My suspicion is that the text field doesn't get the onChange event from the redux-form but I couldn't find any clue what am I doing good.
My code is:
import React from 'react'
import { Button, Modal, Form, Message } from 'semantic-ui-react'
import { Field, reduxForm } from 'redux-form'
const renderField = ({ input, label, type, meta: { touched, error, warning } }) => {
console.log(input)
return (
<Form.Field>
<label>{label}</label>
<input {...input} placeholder={label} type={type} />
{touched && (error && <Message error>{error}</Message>)}
</Form.Field>
)}
let AddNewModal = (props) => {
const { handleSubmit, pristine, submitting, closeNewSite, isAddNewOpen, submit } = props
return (
<Modal dimmer='blurring' open={isAddNewOpen} onClose={closeNewSite}>
<Modal.Header>Add a new site</Modal.Header>
<Modal.Content>
<Form onSubmit={handleSubmit}>
<Form.Group widths='equal'>
<Field name='domain' type='text' component={renderField} label='Domain' />
<Field name='sitemap' type='text' component={renderField} label='Sitemap URL' />
</Form.Group>
/**
* Other fields
* /
<Button type='submit' disabled={pristine || submitting}>Save</Button>
</Form>
</Modal.Content>
<Modal.Actions>
<Button color='black' onClick={closeNewSite} content='Close' />
<Button positive icon='save' labelPosition='right' onClick={submit} content='Save' disabled={pristine || submitting} />
</Modal.Actions>
</Modal>
)
}
export default reduxForm({
form: 'newsite'
})(AddNewModal)
I added the reducer and still got the same issue. At last, I found it must add the attr 'form'.
const reducers = {
routing,
form: formReducer
};
I found the problem. I forgot to inject the redux-form's reducer.
I actually had a similar issue. I will post the code that I am working on for form validation with V6 of redux-form. It works right now but the things you want to look at are componentDidMount, handleInitialize, and handleFormSubmit. Where I figured this out link.
/**
* Created by marcusjwhelan on 10/22/16.
*/
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { reduxForm, Field } from 'redux-form'; // V6 !!!!!!!!
import { createPost } from '../actions/index';
const renderInput = ({ input, label, type, meta: {touched, invalid, error }}) => (
<div className={`form-group ${touched && invalid ? 'has-danger' : ''}`}>
<label>{label}</label>
<input className="form-control" {...input} type={type}/>
<div className="text-help" style={{color: 'red'}}>
{ touched ? error : '' }
</div>
</div>
);
const renderTextarea = ({ input, label, type, meta: {touched, invalid, error }}) => (
<div className={`form-group ${touched && invalid ? 'has-danger' : ''}`}>
<label>{label}</label>
<textarea className="form-control" {...input}/>
<div className="text-help" style={{color: 'red'}}>
{ touched ? error : '' }
</div>
</div>
);
class PostsNew extends Component{
componentDidMount(){
this.handleInitialize();
}
handleInitialize(){
const initData = {
"title": '',
"categories": '',
"content": ''
};
this.props.initialize(initData);
}
handleFormSubmit(formProps){
this.props.createPost(formProps)
}
render(){
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit(this.handleFormSubmit.bind(this))}>
<h3>Create A New Post</h3>
<Field
label="Title"
name="title"
type="text"
component={renderInput} />
<Field
label="Categories"
name="categories"
type="text"
component={renderInput}
/>
<Field
label="Content"
name="content"
component={renderTextarea}
/>
<button type="submit" className="btn btn-primary" >Submit</button>
</form>
);
}
}
function validate(formProps){
const errors = {};
if(!formProps.title){
errors.title = 'Enter a username';
}
if(!formProps.categories){
errors.categories = 'Enter categories';
}
if(!formProps.content){
errors.content = 'Enter content';
}
return errors;
}
const form = reduxForm({
form: 'PostsNewForm',
validate
});
export default connect(null, { createPost })(form(PostsNew));
You need to connect form reducer to your combine reducers
form: formReducer
import { combineReducers } from 'redux';
import { reducer as formReducer } from 'redux-form';
import authReducer from './authReducer';
import productsReducer from './productsReducer';
export default combineReducers({
auth: authReducer,
form: formReducer,
products: productsReducer,
});