Hi I am trying to implement multiple redux forms. But I am getting the same redux form in the output. Could someone look into this and tell me where I am going wrong:
Form 1: Signup.js
import React from 'react';
import {Field,reduxForm} from 'redux-form';
const validate = values =>{
const errors={};
if(!values.username){
errors.username="Please Enter Username";
}else if(values.username.length<5){
errors.username='Please enter atlease 5 characters';
}
if (!values.email) {
errors.email = 'Required'
} else if (!/^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
errors.email = 'Invalid email address'
}
if(!values.password){
errors.password='Please enter password'
}
return errors;
}
const renderField = ({ input, label, type, meta: { touched, error } }) => (
<div>
<label>{label}</label>
<div>
<input {...input} placeholder={label} type={type}/>
{touched && ((error && <span>{error}</span>))}
</div>
</div>
)
const SyncValidationForm = (props) => {
const { handleSubmit, pristine, reset, submitting } = props
return (
<form onSubmit={handleSubmit}>
<Field name="username" type="text" component={renderField} label="Username"/>
<Field name="email" type="email" component={renderField} label="Email"/>
<Field name="password" type="password" component={renderField} label="Password"/>
<div>
<button type="submit" disabled={submitting}>Submit</button>
<button type="button" disabled={pristine || submitting} onClick={reset}>Clear Values</button>
</div>
</form>
)
}
export default reduxForm ({
form: 'syncValidation',
validate
})(SyncValidationForm)
Form 2: Login.js
import React from 'react';
import {Field, reduxForm} from 'redux-form';
const renderField = ({input, label, type})=>{
<div>
<label>{label}</label>
<div>
<input {...input} placeholder={label} type={type}/>
</div>
</div>
}
const Login = (props) =>{
const {handleSubmit} = this.props;
return(
<form onSubmit={handleSubmit}>
<div>
<Field name='username' component={renderField} type='text' label='Username'/>
<Field name='password' type='password' component={renderField} label='Password'/>
</div>
<div>
<button type='submit' disabled={submit}>Submit</button>
</div>
</form>
)
}
export default reduxForm ({
form:'login'
})(Login);
Rendering Component: Homepage.js
import React from 'react';
import {connect} from 'react-redux';
import SyncValidationForm from "../Form/signup";
import Login from "../Form/signup";
class Homepage extends React.Component{
render(){
return(
<div>
<SyncValidationForm onSubmit={this.props.addition}/>
<Login />
</div>
)
}
}
var matchStatetoProps = state =>{
return {root:state.root}
}
var matchDispatchtoProps = dispatch =>{
return{addition:(values)=>dispatch({type:'ADD',payload:values})}
}
export default connect(matchStatetoProps,matchDispatchtoProps)(Homepage);
Store:
import { createStore, combineReducers } from 'redux';
import { reducer as reduxFormReducer1 } from 'redux-form';
import { reducer as reduxFormReducer2 } from 'redux-form';
import rootReducer from '../Reducers/rootReducer'
const reducer = combineReducers({
form: reduxFormReducer1,
login:reduxFormReducer2,
root: rootReducer
});
const store = (window.devToolsExtension
? window.devToolsExtension()(createStore)
: createStore)(reducer);
export default store;
Now its giving an output something like this:
Could someone help me in where I am going wrong
Sorry I was importing the wrong form.
Related
I am using react-final-form to create Registration and Login Forms. I have created file called validators with 3 functions: required, allowedEmails, and validatePassword length. Then I used them in my fields with validate={required} or validate={this.composeValidators(required, validatePasswordLength)}, if I wanted to use more than two validators for my fields.
I have 5 fields: FirstName, LastName, Username, Email and password. At the beginning when the fields are empty everything works well. All of them show error:
"This field is required"
but when I try to enter some value in the specific field, the error for that field still remains.
Here is sandbox link to my project https://codesandbox.io/s/forma-ktvjq
This are functions in my validators file:
export function validateEmail(email) {
var re = /^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(String(email).toLowerCase());
}
export const required = v => {
if(!v || v === ' '){
return 'This field is requireddd';
}
return undefined;
}
export const allowedEmails = v =>{
if (v === validateEmail) {
return "email is not valid";
}
return undefined;
};
export const validatePasswordLength = v => {
if(v){
if(v.length<8){
return "Password has to be atleast 8 charachters";
}
return "Password accepted";
}
import validators, { required, validatePasswordLength, allowedEmails, validateEmail } from '../../validators';
import LoginForm from '../LoginForm';
// import Container from 'react-bootstrap/Container';
// import Row from 'react-bootstrap/Row';
// import Col from 'react-bootstrap/Col';
import React, { Component } from 'react';
import { Form, Field } from 'react-final-form';
import { InputPassword, InputEmail, InputUsername, InputFirstName, InputLastName, InputField} from '../.././../components/InputFields';
import Button from 'react-bootstrap/Button'
import { metaProperty } from '#babel/types';
import { withRouter } from 'react-router-dom';
class RegisterForm extends Component {
sleep = ms => new Promise(res => setTimeout(res, ms));
newPage = (newPage) => {
this.props.history.push('/login');
};
handleSubmit = async (values,e) => {
e.preventDefault()
await this.sleep(300);
console.log("values", values);
this.newPage();
};
composeValidators = (...validators) => value => validators.reduce((error, validator) => error || validator(value), undefined);
render(){
return (
<div>
<h1>đ Register Form</h1>
<br>
</br>
<br></br>
<Form
onSubmit={this.handleSubmit.bind(this)}
render={ ( { handleSubmit, values, submitting, meta }) => (
<form onSubmit={handleSubmit}>
<Field
name="firstName"
component={InputField}
hintText="First Name"
floatingLabelText="First Name"
validate={required}
type="text"
/>
<Field
name="lastName"
component={InputField}
hintText="Last Name"
floatingLabelText="Last Name"
validate={required}
type="text"
/>
<Field
name="username"
component={InputField}
hintText="UserName"
floatingLabelText="username"
validate={required}
type="text"
/>
<Field
name="password"
component={InputField}
hintText="Password"
floatingLabelText="Password"
validate={this.composeValidators(required, validatePasswordLength)}
type="password"
/>
<Field
name="email"
component={InputField}
hintText="email"
floatingLabelText="Email"
validate={this.composeValidators(required, allowedEmails)}
type="email"
/>
<Button size="lg" type="submit">Register</Button>
</form>
) } />
</div>
);
};
}
export default RegisterForm;
Here is also my third party component that i am using in Field as component.
import { Form, Field } from 'react-final-form';
import LoginForm from '../containers/forms/LoginForm';
import RegisterForm from '../containers/forms/RegisterForm';
import './InputFields.css'
export const InputField = (props) => {
console.log("PROOOPS ", props);
return(
<div>
<InputGroup size="lg" className="mb-4">
<FormControl
placeholder={props.floatingLabelText}
type={props.input.type}
/>
</InputGroup>
<div className="ValidatorStyle" >
{props.meta.error && props.meta.touched && <span>{props.meta.error}</span>}
</div>
</div>
)}
I don't get any error, but the field value does not get updated.
In InputField.js you need to spread the input props on InputGroup, like:
<InputGroup size="lg" className="mb-4" {...props.input}>
(That includesvalue, onChange and more)
I want to send the input values to the api.
I used the code from below link, to get the input values in the submit method, but though the submit method gets called, the variable is empty.
How to handle redux form submitted data
index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import ContactForm from "./ContactForm";
import * as serviceWorker from "./serviceWorker";
import { createStore } from "redux";
import { Provider } from "react-redux";
import rootReducers from "./reducers";
const store = createStore(rootReducers);
ReactDOM.render(
<Provider store={store}>
<ContactForm />
</Provider>,
document.getElementById("root")
);
serviceWorker.unregister();
reducer.js
import { combineReducers } from "redux";
import { reducer as formReducer } from "redux-form";
const rootReducer = combineReducers({
form: formReducer
});
export default rootReducer;
ContactForm.js
import React, { Component } from "react";
import { reduxForm } from "redux-form";
class ContactForm extends Component {
submit(formValues) {
console.log(formValues);
}
render() {
const {
fields: { firstName, lastName, email },
handleSubmit
} = this.props;
return (
<form onSubmit={handleSubmit(this.submit)}>
<div>
<label>First Name</label>
<input type="text" placeholder="First Name" {...firstName} />
</div>
<div>
<label>Last Name</label>
<input type="text" placeholder="Last Name" {...lastName} />
</div>
<div>
<label>Email</label>
<input type="email" placeholder="Email" {...email} />
</div>
<button type="submit">Submit</button>
</form>
);
}
}
ContactForm = reduxForm({
form: "contact",
fields: ["firstName", "lastName", "email"]
})(ContactForm);
export default ContactForm;
I am getting formValues as empty. Could anyone please help me with it?
It seems the example was for version 5.3.1 of Redux-form, while I had installed 8.1.0 version.
Below is the working code:
import React, { Component } from "react";
import { Field, reduxForm } from "redux-form";
const submit = values => {
console.log(values);
};
class ContactForm extends Component {
render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit(submit)}>
<div>
<label>First Name</label>
<Field name="firstName" component="input" type="text" />
</div>
<div>
<label>Last Name</label>
<Field name="lastName" component="input" type="text" />
</div>
<div>
<label>Email</label>
<Field name="email" component="input" type="email" />
</div>
<button type="submit">Submit</button>
</form>
);
}
}
export default reduxForm({
form: "contact"
})(ContactForm);
You probably need to use instead of inside the form, to connect your input data with redux store.
https://redux-form.com/8.3.0/examples/submitvalidation/
im work with Redux and React, in CRUD operations with API , createPost return null into the values of title, categories, and content with Redux-Form?
I could help, I do not know what my mistake ?
actions file index.js
export const CREATE_POST = 'CREATE_POST';
const URL = 'http://reduxblog.herokuapp.com/api';
const API_KEY = '1234557';
export function createPost(props) {
const request = axios
.post(`${URL}/posts?${API_KEY}`, props)
.then( res => { console.log(res) })
return {
type: CREATE_POST,
payload: request,
};
}
component file newPost.js
import React from 'react';
import { reduxForm } from 'redux-form';
import {crearPost} from '../acciones/index';
import {connect} from 'react-redux';
class NuevoPost extends React.Component {
onSubmit(values) {
this.props.crearPost(values)
}
render() {
const {fields: {
title, categories, content} ,
handleSubmit } = this.props;
return (
<form onSubmit={
handleSubmit(this.onSubmit.bind(this))}>
<h3>Crea un nuevo Post.</h3>
<div className='form-group'>
<label
>titulo</label>
<input
type='text'
className='form-control'
{...title}
/>
</div>
<div className='form-group'>
<label
>Categoria</label>
<input
type='text'
className='form-control'
{...categories}
/>
</div>
<div className='form-group'>
<label
>Contenido</label>
<textarea
type='text'
className='form-control'
{...content}
/>
</div>
<button
type="submit"
className="btn btn-info"
>Postear</button>
</form>
)
}
}
export default reduxForm({
form: 'newPost',
fields: ['title', 'categories', 'content']
})(connect(null, { crearPost })(NuevoPost));
You need to use redux-form Field here
import { reduxForm, Field } from 'redux-form';
<div className='form-group'>
<label>Categoria</label>
<Field
type='text'
className='form-control'
component={'input'}
/>
</div>
I have a contact page on which I have a contact form defined like this:
import React from "react";
import { Field, reduxForm } from "redux-form";
import Recaptcha from "react-recaptcha";
const required = value => (value ? undefined : "This field is required.");
const email = value => value && !/^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(value) ? "Invalid email address." : undefined;
const renderInput = ({
input,
label,
type,
meta: { touched, error }
}) => (
<div className="form-group">
<label className="col-sm-2 control-label">{ label }</label>
<div className="col-sm-10">
{ (type == "text" || type == "email") ? <input { ...input } type={ type } /> : <textarea { ...input }></textarea> }
{ touched && ((error && <span className="contact-form-error-message">{ error }</span>)) }
</div>
</div>
);
const captcha = (props) => (
<div className="form-group">
<label className="col-sm-2 control-label"></label>
<div className="col-sm-10">
<Recaptcha render="explicit" onloadCallback={ console.log.bind(this, "reCAPTCHA loaded.") }
sitekey="XXXXXXXXXXXXXXXXX" onChange={props.input.onChange} />
</div>
</div>
);
const ContactForm = props => {
const { handleSubmit, submitting } = props
return (
<form className="form-horizontal" onSubmit={ handleSubmit }>
<Field
name="name"
type="text"
component={ renderInput }
label="Name:"
validate={ required }
/>
<Field
name="email"
type="email"
component={ renderInput }
label="Email:"
validate={ [required, email] }
/>
<Field
name="subject"
type="text"
component={ renderInput }
label="Subject:"
validate={ required }
/>
<Field
name="message"
type="textarea"
component={ renderInput }
label="Message:"
validate={ required }
/>
<Field name="recaptchacode" component={ captcha } />
<div className="form-group">
<label className="col-sm-2 control-label"></label>
<div className="col-sm-10">
<button type="submit" id="contact-form-button" disabled={ submitting }>Send</button>
</div>
</div>
</form>
)
}
export default reduxForm({
form: "ContactForm"
})(ContactForm);
The problem is I cannot seem to get the recaptchacode field in the values object when I click the submit button. How do I bind the value of the Recaptcha component to redux-form so that it puts it in the values object?
And since StackOverflow wants me to add more explanation to this because there's too much code, I am writing this text.
So the answer in short as I have managed to get this thing working. There are two npm packages for implementing recaptcha in react:
react-recaptcha and react-google-recaptcha. You want the second one and not the first one (which was my problem and doesn't work with redux-form) and then you want to follow this tutorial: https://github.com/erikras/redux-form/issues/1880
Hope this helps someone.
Hereâs how I integrated Google ReCaptcha with React and redux-forms with Language support. Hope this will help someone.
Versions:
React: 16.5.2
react-google-recaptcha: 1.0.5
react-redux: 5.0.6
redux: 3.7.2
redux-form: 7.2.0
Redux form:
import React from 'react';
import {
reduxForm,
Field,
formValueSelector,
change,
} from 'redux-form';
import { testAction } from â/actions';
import { connect } from 'react-redux';
import Captcha from './Captcha';
const validate = values => {
const errors = {};
if (!values.captchaResponse) {
errors.captchaResponse = 'Please validate the captcha.';
}
return errors;
};
let TestForm = (props) => {
const {
handleSubmit,
testAction,
language, //extract language from props/or hard code it in Captcha component
} = props;
return (
<Form onSubmit={ handleSubmit(testAction)}>
<Field component={Input} name=âother_input_nameâ type="text" required/>
<Field dispatch={props.dispatch} component={Captcha} change={change} language={language} name="captchaResponse"/> {/* Pass redux-forms change and language to the Captcha component*/}
<Button type="submit">{âValidateâ}</Button>
</Form>
);
};
const selector = formValueSelector('testForm');
TestForm = connect(
state => ({
recaptchaValue: selector(state, 'captchaResponse'),
}),
{ testAction: testAction }
)(TestForm);
export default reduxForm({
form: âtestFormâ,
validate,
enableReinitialize: true,
})(TestForm);
Captcha component:
import React, { Component } from 'react';
import ReCAPTCHA from 'react-google-recaptcha';
import styled from 'styled-components';
import { change } from 'redux-form';
class Captcha extends Component {
constructor(props) {
super(props);
window.recaptchaOptions = { lang: this.props.language }; //set language that comes from props E.g.: fr/es/en etc..
}
onChange = (value) => {
this.props.meta.dispatch(change(âtestFormâ, 'captchaResponse', value));
};
render() {
const { meta: { touched, error } } = this.props;
return (
<CaptchaWrapper>
<ReCAPTCHA
sitekey={âxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxâ}
onChange={response => this.onChange(response)}
/>
<ErrorMessage>{ touched ? error : '' }</ErrorMessage>
</CaptchaWrapper>
);
}
}
const CaptchaWrapper = styled.div`
`;
const ErrorMessage = styled.p`
color: red;
`;
export default Captcha;
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,
});