Redux-form onSubmit nothing happens - reactjs

I would like to ask, what I miss on my code. It seems submitForm function is not working/triggering when I submit the form. I can't get values from my form fields. Here's my code:
import React from 'react';
import { reduxForm,reset, Field } from 'redux-form';
class FormProfile extends React.Component {
submitForm(formProps){
console.log(formProps);
}
render(){
const { error, handleSubmit } = this.props;
return (
<form onSubmit={this.submitForm.bind(this)}>
<Row>
<Col lg={6}>
<Field name="name" type="text" component={TextBoxComponent} placeholder="Compay Name" label="* Company Name" required />
<Field name="website" type="text" component={TextBoxComponent} placeholder="www.yourdomain.com" label="Website" />
<Field name="email" type="text" component={TextBoxComponent} placeholder="How can we contact your Company" label="* Contact Email" required />
</Col>
</Row>
</form>
);
}
}
const form = reduxForm({
form: 'CreateCompanyProfileForm',
validate
});
function validate(formProps){
const error = {};
return error;
}
export default (form(FormProfile));
TextBox Componen
import React from "react";
class TextBoxComponent extends React.Component {
render(){
return (
<div className="form-group">
<label className="control-label">{this.props.label}</label>
{ this.props.sublabel !== undefined ?
<em className="text-info"> { this.props.sublabel }</em>
:null}
<input { ...this.props } type={this.props.type} placeholder={this.props.placeholder} className="form-control"/>
{ this.props.required && <span className="text-error"></span> }
</div>
);
}
}
export default TextBoxComponent;

You should modify this line:
<form onSubmit={this.submitForm.bind(this)}>
to:
<form onSubmit={handleSubmit}>
then you can remove:
submitForm(formProps){
console.log(formProps);
}
Then you can create a new component to wrap redux form component:
class SamplePage extends React.Component {
handleSubmit = (values) => {
// Do something with the form values
console.log(values);
}
render() {
return (
<FormProfile onSubmit={this.handleSubmit} />
);
}
}
Anyway, you should check the example from Redux-form docs: http://redux-form.com/6.5.0/docs/GettingStarted.md/

Related

Validation does not get new fields value

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)

How To Implement Google reCAPTCHA With Redux Form

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;

Why can't I type in my fields?

I am using redux-form and I cannot type inside of my inputs after I add the initialize method and componentDidUpdate(). When I try to type in my email no characters appear. I am guessing all the inputs become controlled? If so how would I handle that?
import { reduxForm, Field, initialize } from 'redux-form';
const CustomComponent = function(field) {
return(
<div>
<input { ...field.input } type={field.type} placeholder={field.placeholder} />
</div>
);
}
//class instantiation
componentDidUpdate(){
this.handleInitialize();
}
handleInitialize() {
const initData = {
"name": this.props.name
};
this.props.initialize(initData);
}
render() {
const { handleSubmit } = this.props;
return (
<div>
<form onSubmit={handleSubmit(this.onSubmit)}>
<div>
<Field name="name" component={CustomComponent} type="text" placeholder="Name" />
<Field name="email" component={CustomComponent} type="email" placeholder="Email" />
</div>
<button type="submit">Submit</button>
</form>
</div>
);
}
You can't define your CustomComponent inside the render() method. That will cause your component to lose focus when you first start typing into an input.
Have you set up the reducer properly in your Redux config?

redux-form - onSubmit doesnt work

I'm using redux-form and I just cant get the onSubmit fuction to work.
EDIT: My problem is that the function is not being called, i put debugger on the onSubmit and it doesnt get there.
here is my form:
class userForm extends Component {
onSubmit(values) { // do here something }
render() {
const { handleSubmit } = this.props;
return <form onSubmit={handleSubmit(this.onSubmit)}>
<Field name='id'
component={TextField}
label='id'/>
<Field name='name'
component={TextField}
label='name' />
<button type='submit'>Submit</button>
</form>
}
}
export default reduxForm({
form: 'userForm'
})(userForm);
But it never gets to the onSubmit method.
What am I doing wrong?
you just need to add .bind keyword after submit,
class userForm extends Component {
onSubmit(values) { // do here something }
render() {
const { handleSubmit } = this.props;
return <form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<Field name='id'
component={TextField}
label='id'/>
<Field name='name'
component={TextField}
label='name' />
<button type='submit'>Submit</button>
</form>
}
}
export default reduxForm({
form: 'userForm'
})(userForm);
This is an edited version of the pattern I use.
Note the use of the bind keyword.
Generally I use redux to manage state, and would also use an action inside the function handleFormSubmit. But this should get you on the right track.
import React, { Component } from 'react';
import { reduxForm } from 'redux-form';
class Userform extends Component {
static handleFormSubmit({ id, name}) {
console.log({id, name});
}
render () {
const { handleSubmit, fields: { id, name }} = this.props;
return(
<form onSubmit={handleSubmit(Userform.handleFormSubmit.bind(this))}>
<fieldset>
<label>Id:</label>
<input {...id}/>
</fieldset>
<fieldset>
<label>Name:</label>
<input {...name} />
</fieldset>
<button action="submit">Submit</button>
</form>
);
}
}
export default reduxForm({
form: 'userform',
fields: ['id', 'name']
})(Userform);

Redux-form : get information from a custom form with interlock components

I m using redux-form from : http://redux-form.com/4.2.0 and I tried the simple contact form example, that you can see here :
import React, {Component} from 'react';
import {reduxForm} from 'redux-form';
import TitleBlock from './TitleBlock'
class ContactForm extends Component {
render() {
const {fields: {firstName, lastName, email}, handleSubmit} = this.props;
return (
<form onSubmit={handleSubmit}>
<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>
<TitleBlock />
<button type="submit">Submit</button>
</form>
);
}
}
ContactForm = reduxForm({ // <----- THIS IS THE IMPORTANT PART!
form: 'contact', // a unique name for this form
fields: ['firstName', 'lastName', 'email'] // all the fields in your form
})(ContactForm);
export default ContactForm;
It works very well, but I want to separate my component to create forms with custom blocks, for exemple I created a title block here :
import React, { Component, PropTypes } from 'react'
import {reduxForm} from 'redux-form';
export const fields = ['title', 'description'];
export default class TitleBlock extends Component {
static propTypes = {
fields: PropTypes.object.isRequired,
};
render() {
const {
fields: {title,description},
} = this.props;
return (
<div>
<div>
<label>Title</label>
<div>
<input type="text" placeholder="Title" {...title}/>
</div>
</div>
<div>
<label>Description</label>
<div>
<input type="text" placeholder="Description" {...description}/>
</div>
</div>
</div>
)
}
}
export default reduxForm({
form: 'TitleBlock',
fields
})(TitleBlock);
And I want to interlock this TitleBlock to my contact Form, is it possible to do that and manage all the informations in one single submit function ?
Instead of connecting TitleBlock to redux-form, you can have your ContactForm component pass the fields prop into TitleBlock like so:
class ContactForm extends React.Component {
...
render() {
return (
<div>
<TitleBlock fields={this.props.fields} />
...
</div>
);
}
}
export default reduxForm({...})(ContactForm)
And your TitleBlock component could look like this:
export default class TitleBlock extends Component {
static propTypes = {
fields: PropTypes.object.isRequired,
};
render() {
const { fields: { title, description } } = this.props;
return (
<div>
<div>
<label>Title</label>
<div>
<input type="text" placeholder="Title" {...title}/>
</div>
</div>
<div>
<label>Description</label>
<div>
<input type="text" placeholder="Description" {...description}/>
</div>
</div>
</div>
);
}
}

Resources