I want to stop anything onblur function if validation fails. i am not sure how to do this
here is the field
<Field
label="Demand Ref"
name="demand_ref"
component={this.renderTextField}
type="text"
onBlur={e => this.onAfterSaveCell(e, 'demand_ref')}
onFocus={e => this.onBeforeSaveCell(e, 'demand_ref')}
validate={[validateDemandRef]}
maxlength="15"
/>
if validate fails i don't want anything in onBlur to run. how can i do this?
UPDATE
If i am using validate={[validateDemandRef]} what do i pass into ...some validation
UPDATE 2
how woudl this look if it is a class const MyComponent = ({ handleSubmit, valid }) => (. MyComponent is a class
Use the isValid or isInvalid selectors (https://redux-form.com/7.4.2/docs/api/selectors.md/)
import React from 'react';
import { compose } from 'redux';
import { reduxForm, isValid } from 'redux-form';
const MyComponent = ({ handleSubmit, valid }) => (
<form onSubmit={handleSubmit}>
<Field
label="Demand Ref"
name="demand_ref"
component={this.renderTextField}
type="text"
onBlur={valid && e => this.onAfterSaveCell(e, 'demand_ref')}
onFocus={e => this.onBeforeSaveCell(e, 'demand_ref')}
validate={[validateDemandRef]}
maxlength="15"
/>
<button type="submit">Submit</button>
</form>
);
const FORM_NAME = 'my-form';
export default compose(
reduxForm({
form: FORM_NAME,
}),
connect(state => ({
valid: isValid(FORM_NAME)(state), // also there is an isInvalid selector
})),
)(MyComponent);
For stateful component implementation
import React, { PureComponent } from 'react';
import { compose } from 'redux';
import { reduxForm, isValid } from 'redux-form';
class MyComponent extends PureComponent {
render() {
const { handleSubmit, valid } = this.props;
return (
<form onSubmit={handleSubmit}>
<Field
label="Demand Ref"
name="demand_ref"
component={this.renderTextField}
type="text"
onBlur={valid && e => this.onAfterSaveCell(e, 'demand_ref')}
onFocus={e => this.onBeforeSaveCell(e, 'demand_ref')}
validate={[validateDemandRef]}
maxlength="15"
/>
<button type="submit">Submit</button>
</form>
);
}
}
const FORM_NAME = 'my-form';
export default compose(
reduxForm({
form: FORM_NAME,
}),
connect(state => ({
valid: isValid(FORM_NAME)(state), // also there is an isInvalid selector
})),
)(MyComponent);
Related
I'm trying to understand why dispatch is not available in my actions to no avail. Here is what I tried.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Field, Form } from 'react-final-form';
import { createProfile } from '../../actions/actions_members';
const onSubmit = async (values) => {
createProfile(values)
}
const Signup = () => (
<Form
onSubmit={onSubmit}
render={({ handleSubmit, submitting, pristine, values }) => (
<form onSubmit={handleSubmit} >
<label>Email:</label>
<Field type='text' className='input' component="input" type="text" name='email'/>
<label>Password:</label>
<Field className='input' component="input" type="password" name='password' />
{/*<label>Confirm password:</label>
<input type='password' className='input' name='password' {...password} />*/}
<button type="submit" disabled={submitting || pristine}>
Submit
</button>
</form>
)}
/>
)
export default connect()(Signup)
And here is my actions_members file
import * as C from './actions_const.js'
import { post, get } from '../helpers/apiConnection.js'
const createProfile = (value, dispatch) => {
var data = {
ep: "EP_SIGNUP",
payload : {
email: value.email,
password: value.password
}
}
post(data).then((result)=>dispatch({type:C.MEMBER_CREATE}));
}
export { createProfile }
I don't know how to pass dispatch to my createProfile action
You just have to pass it in from the onSubmit function.
const dispatch = useDispatch();
const onSubmit = async (values) => {
createProfile(values, dispatch)
}
The other option would be to import the store in your action_members file and use store.dispatch, which amounts to the same thing.
import * as C from './actions_const.js'
import { post, get } from '../helpers/apiConnection.js'
import store from '../whereverReduxStoreIsSetup.js';
const createProfile = (value) => {
var data = {
ep: "EP_SIGNUP",
payload : {
email: value.email,
password: value.password
}
}
post(data).then((result)=>store.dispatch({type:C.MEMBER_CREATE}));
}
export { createProfile }
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.
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,
});
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);