Dispatch an action onBlur with redux form - reactjs

i have an input component which i made compatible with redux form like this:
const renderInput = ({ input, label, type, meta: { touched, error } }) => (
<div className="input-row">
<div>
<input
{...input}
className="form-control input-box__input"
type={type}
placeholder={label}
autoComplete="off"
onBlur={input.onBlur}
/>
{touched && error &&
<span className="error">
<FormattedMessage
id={`${error}`}
defaultMessage={`_${error}_`}
description={`the message for the ${error}`}
/>
</span>}
</div>
</div>
);
And i using it like this:
<Field
name="username"
type="text"
component={renderInput}
onBlur={value => usernameClickHandler(value)}
/>
When i leave the field the action was never been dispatched.
What am i missing?
The action is being dispatched here:
const mapDispatchToProps = dispatch => (
{
submitSecondRegister: (secondRegisterData) => {
dispatch(secondRegister(secondRegisterData));
},
usernameClickHandler: (name) => {
dispatch(userNameExistence(name));
}
}
);
All i see is that the action is never dispatched. I assume that my onBlur is not working

Related

How to add react-phone-number-input to -react-final-form?

I'm currently creating a form using react-final-form and trying to use react-phone-number-input with it through integration as an adapter, as displayed through this example.
I attempted to use the example to learn how it is done, but I'm not sure how to access the component and create the adapter for it properly.
import React from 'react';
import { Form, Field } from 'react-final-form';
import PhoneInput from 'react-phone-number-input';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
const onSubmit = async values => {
await sleep(300)
window.alert(JSON.stringify(values, 0, 2))
}
const PhoneAdapter = ({ input, meta, ...rest }) => (
<PhoneInput
{...input}
{...rest}
value={input.value}
onChange={(event, value) => input.onChange(value)}
/>
)
class ContactForm extends React.Component {
render() {
return (
<>
<Form
onSubmit={onSubmit}
initialValues={{ }}
render={({ handleSubmit, form, submitting, pristine, values }) => (
<form onSubmit={handleSubmit}>
<fieldset>
<Field component={PhoneAdapter} />
</fieldset>
<fieldset>
<button type="submit" disabled={submitting || pristine}>
Submit
</button>
</fieldset>
<pre>{JSON.stringify(values, 0, 2)}</pre>
</form>
)}
/>
</>
);
}
}
export default ContactForm;
Update: July 2019
Apparently, all you need to do is to spread the input property of Field. Works flawlessly. Learn about spreading if you're not familiar with it.
const PhoneAdapter = ({ input }) => (
<PhoneInput {...input} />
)
<Field name="phone" placeholder="Enter phone number" component={PhoneAdapter} />
I ended up experimenting with the FieldRenderProps props until it worked out. I wasn't so sure whether it would work or not, as react-phone-number-input is two elements in a component. I thought it would implement the input on only one of the elements.
By using input, I gain access to the input's props. Hence, I called upon it's value, as the default looks like so:
<PhoneInput
placeholder="Enter phone number"
value={ this.state.value } // This is what I called.
onChange={ value => this.setState({ value }) }/>
I then did the same for the onChange function prop.
const PhoneAdapter = ({ input }) => (
<PhoneInput value={input.value.value} onChange={value => input.onChange(value)} />
)
Finally, I used the component adapter like so:
<Field name="phone" placeholder="Enter phone number" component={PhoneAdapter} />

How to change a field in a redux-form?

In my react component I am trying to set a field called 'total'. I have imported the change action as a prop into my component:
import React, { Component, Fragment } from 'react'
import { Field, FieldArray, reduxForm, getFormValues, change } from 'redux-form'
import { connect } from 'react-redux'
import { CalcTotal } from './calculationHelper';
const renderField = ({ input, label, type, meta: { touched, error } }) => (
<div>
<label>{label}</label>
<div>
<input {...input} type={type} placeholder={label} />
{touched && error && <span>{error}</span>}
</div>
</div>
)
const renderMods = ({ fields, meta: { error, submitFailed } }) => (
<Fragment>
<ul>
<li>
<button type="button" onClick={() => fields.push({})}>
Add Modification
</button>
{submitFailed && error && <span>{error}</span>}
</li>
{fields.map((mod, index) => (
<li key={index}>
<button
type="button"
title="Remove Mod"
onClick={() => fields.remove(index)}
/>
<h4>Mod #{index + 1}</h4>
<Field
name={`${mod}.lastYear`}
type="number"
component={renderField}
label="Last Year"
/>
<Field
name={`${mod}.currentYear`}
type="number"
component={renderField}
label="Current Year"
/>
<Field name={`${mod}.type`} component="select" label="Type">
<option />
<option value="-">Expense</option>
<option value="+">Income</option>
<option value="-">Tax</option>
</Field>
</li>
))}
</ul>
<Field
name="total"
type="number"
component="input"
label="Total modifications"
text="0"
/>
</Fragment>
)
class FieldArraysForm extends Component {
render() {
const { handleSubmit, formValues, change } = this.props
if (formValues) {
console.log('formvalues', formValues);
const test = CalcTotal(2000);
console.log('calc=', test);
debugger
this.props.change('fieldArraysForm', 'total', 5000)
}
return (
<form onSubmit={handleSubmit}>
{/* <button onClick={this.changeStuff}>set total</button> */}
<FieldArray name="mods" component={renderMods} />
<div>
<button type="submit" >
Submit
</button>
</div>
</form>
)
}
}
const mapStateToProps = (state) => ({
formValues: getFormValues('fieldArraysForm')(state),
});
const mapDispatchToProps = {
change
};
// const Example = reduxForm({
// form: 'fieldArraysForm', // a unique identifier for this form
// })(FieldArraysForm)
// const ConnectedForm = connect(
// mapStateToProps,
// mapDispatchToProps,
// )(Example);
// export default ConnectedForm
export default reduxForm({
form: "fieldArraysForm"
})(
connect(
mapStateToProps,
mapDispatchToProps
)(FieldArraysForm)
);
The line where the code fall into an infinite loop:
this.props.change('fieldArraysForm', 'total', 5000)
How /where do I put this statement to make sure the 'total' field is changed and not get into a loop?Which React lifecycle event would suit? I want to fire this whenever there is a form change on any field.
You'll need to move your statement out of the render method and into the componentDidUpdate lifecycle method (you also need an if statement to prevent an infinite loop):
componentDidUpdate(prevProps) {
if (this.props.someValue !== prevProps.someValue) {
this.props.change("formName", "formField", "newFormValue");
}
}
Working example: https://codesandbox.io/s/r5zz36lqnn (selecting the Has Email? radio button populates the email field with test#example.com, unselecting the radio button resets the email field to "")

Formik form not updating fields upon edit

I've been trying to rewrite my beginner form in React to use Formik.
I've gotten to the state that the form is being rendered, however, for some reason, I can't update the fields. It's clear that I made a mistake somewhere that prevents Formik from updating the state. What am I missing?
An example form component:
export const TextBox: React.SFC<FieldProps<any> & CustomFormElementProps> = ({
field, // { name, value, onChange, onBlur }
form: { touched, errors },
loading,
...props
}) => (
<div className="row form-group" key={field.name}>
<label className="col-sm-2 control-label">
<ReactPlaceholder showLoadingAnimation ready={!loading} type="text" rows={1} className="control-label">
{props.label}
</ReactPlaceholder>
</label>
<div className="col-sm-10">
<ReactPlaceholder showLoadingAnimation ready={!loading} type="text" rows={1} className="form-control">
<input type="text"
disabled={props.disabled}
className="form-control"
id={field.name}
onChange={field.onChange}
onBlur={field.onBlur} {...props} />
{touched[field.name] && errors[field.name] && <span className="text-danger">{errors[field.name]}</span>}
</ReactPlaceholder>
</div>
</div>
);
The form is initialized in another component (which acts as a page template for the website);
renderFormElements() {
var formFields = this.props.detailsElements.map((item) => {
switch (item.type) {
case FormElementType.TextLine:
return <TextLine
name={item.name}
label={item.label}
disabled={!this.state.editMode}
loading={item.loading}
value={item.defaultValue}
key={'TextBox_' + item.name}
/>
case FormElementType.TextBox:
return <Field
type="text"
name={item.name}
label={item.label}
component={InputElements.TextBox}
disabled={!this.state.editMode}
loading={item.loading}
value={item.defaultValue}
key={'TextBox_' + item.name}
/>
case FormElementType.DropDown:
return <Field
name={item.name}
label={item.label}
component={InputElements.DropDown}
disabled={!this.state.editMode}
loading={item.loading}
value={item.defaultValue}
options={item.options}
key={'DropDown_' + item.name}
/>
case FormElementType.RadioGroup:
return <Field
type="radio"
name={item.name}
label={item.label}
component={InputElements.RadioGroup}
disabled={!this.state.editMode}
loading={item.loading}
value={item.defaultValue}
options={item.options}
key={'RadioGroup' + item.name}
/>
}
});
var initialValues:{ [k: string]: any } = {};
this.props.detailsElements.map((item) => {
initialValues[item.name] = item.defaultValue;
})
console.log(initialValues);
var formSection =
(<Formik initialValues={initialValues} onSubmit={(values, actions) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2))
actions.setSubmitting(false)
}, 1000)
}}>
<Form key="mainForm">
{formFields}
</Form>
</Formik>)
return formSection;
I was assuming that the onChange event handler was taken care of by Formik, and that, if I didn't want to do special stuff, I did not need to provide anything to this.
What am I missing here?
Thanks!
your formFields function gets all of Formik props goodies.
it contains handleChange - use this handler as your on change.
Also, make sure the field "id" is the same as the values key.
const {
values,
touched,
errors,
dirty,
isSubmitting,
handleChange,
handleBlur,
handleSubmit,
} = this.props;
<FormControl
id="username"
required
placeholder="Enter Username"
value={values.username}
error={touched.username && errors.username}
onChange={handleChange}
onBlur={handleBlur}
/>
try putting the name attribute in the input element
name is what you got from field.name

Copy one Redux Form Value to Another

function mapStateToProps(state) {
let returnObject = {};
if (state && state.form) {
if (
state.form.someFormName &&
state.form.someFormName.values &&
state.form.someFormName.values.fieldNameX &&
state.form.someFormName.values.fieldNameX === "1"
) {
state.form.someFormName.values.fieldNameB =
state.form.someFormName.values.fieldNameA;
state.form.someFormName.values.fieldNameC =
state.form.someFormName.values.fieldNameD;
state.form.someFormName.values.fieldNameF =
state.form.someFormName.values.fieldNameE;
}
}
return returnObject;
}
This is Working Fine on selecting form field i am just copying redux form value to another field,How to do in Efficient Way?This is the Correct way to copy one form field into another ?
You can use formValueSelector to connect to your form value and than dispatch change action creator to update any field with your value.
Here is the example with textboxes(you can update it to use datePicker):
import {change, formValueSelector} from 'redux-form';
let FormName = (props) => {
const {dispatch, handleSubmit, firstValue} = props;
return <form onSubmit={handleSubmit}>
<div>
<label>First Value</label>
<Field
name='firstValue'
component='input'
type='text'
placeholder='First Value'
/>
</div>
<div>
<label>Copy value</label>
<div>
<Field
name='checkbox'
component='input'
type='checkbox'
value='checkboxValue'
onChange={(e) => {
if (e.target.checked) {
dispatch(change('formName', 'secondValue', firstValue));
}
}}
/>
</div>
</div>
<div>
<label>Second Value</label>
<Field name='secondValue' component='input' type='text'/>
</div>
<div>
<button type="submit">Submit</button>
</div>
</form>
};
const selector = formValueSelector('formName');
connect(
state => ({
firstValue: selector(state, 'firstValue'),
})
)(FormName);
This is not the Preferred method to change the state like this (You are mutating the state) Redux 2 Principle,Use this instead:
If you are using radio/checkbox, then onPress of that radio/checkbox you can copy all the field,then dispatch onChange action.
For Eg:
<Field
type="radio"
name="fieldNameX"
value="1"
onRadioPress={this.someMethod}
component={CustomRadioButton}
/>
someMethod() {
let formValues = Object.assign({}, this.props.formValues);
this.props.dispatch(
change("SomeForm", "fieldWantToCopy", value)
);
}

unable to set defaultValue in redux-form-material-ui TextField

I'm unable to set a default value for the textField component.
I tried using default value, but as long as I'm using the redux-form-material-ui it just doesn't work.
I really don't understand what am I doing wrong (seems pretty basic)...
exmaple (just changed their fieldArray example a little):
import React from 'react'
import { Field, FieldArray, reduxForm } from 'redux-form'
import validate from './validate'
import {TextField} from 'redux-form-material-ui'
const renderField = (props) => {
console.log(props);
const { input, label, type, meta: { touched, error } } = props;
console.log(input);
return <div>
<label>{label}</label>
<div>
// Will not show "someValue", it will just be blank
<TextField defaultValue="someValue" {...input} type={type} placeholder={label}/>
{touched && error && <span>{error}</span>}
</div>
</div>
}
const renderMembers = ({ fields, meta: { touched, error, submitFailed } }) => (
<ul>
<li>
<button type="button" onClick={() => fields.push({})}>Add Member</button>
{(touched || submitFailed) && error && <span>{error}</span>}
</li>
{fields.map((member, index) =>
<li key={index}>
<button
type="button"
title="Remove Member"
onClick={() => fields.remove(index)}/>
<h4>Member #{index + 1}</h4>
<Field
name={`${member}.firstName`}
type="text"
component={renderField}
label="First Name"/>
<Field
name={`${member}.lastName`}
type="text"
component={renderField}
label="Last Name"/>
<FieldArray name={`${member}.hobbies`} component={renderHobbies}/>
</li>
)}
</ul>
)
const renderHobbies = ({ fields, meta: { error } }) => (
<ul>
<li>
<button type="button" onClick={() => fields.push()}>Add Hobby</button>
</li>
{fields.map((hobby, index) =>
<li key={index}>
<button
type="button"
title="Remove Hobby"
onClick={() => fields.remove(index)}/>
<Field
name={hobby}
type="text"
component={renderField}
label={`Hobby #${index + 1}`}/>
</li>
)}
{error && <li className="error">{error}</li>}
</ul>
)
const FieldArraysForm = (props) => {
const { handleSubmit, pristine, reset, submitting } = props
return (
<form onSubmit={handleSubmit}>
<Field name="clubName" type="text" component={renderField} label="Club Name"/>
<FieldArray name="members" component={renderMembers}/>
<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: 'fieldArrays', // a unique identifier for this form
validate
})(FieldArraysForm)
Thanks.
I was having the same issue. Just read through the documentation again and saw this
No Default Values
Because of the strict "controlled component" nature of redux-form, some of the Material UI functionality related to defaulting of values has been disabled e.g. defaultValue, defaultDate, defaultTime, defaultToggled, defaultChecked, etc. If you need a field to be initialized to a certain state, you should use the initialValues API of redux-form.
It's probably only one way to make form of editing.
It cannot be restored from initial redux Form values.
Input
export default function ({ input, label, meta: { touched, error }, ...custom }) {
if ( input.value === '' && custom.cvalue ) { // hack for redux form with material components
input.onChange(String(custom.cvalue));
}
return (
<TextField
{...input}
{...custom}
fullWidth={true}
hintText={label}
floatingLabelText={label}
errorText={touched && error}
/>
)
}
Select
export default function ({ input, label, meta: { touched, error }, onChange, children, ...custom }) {
if ( input.value === '' && custom.cvalue ) { // hack for redux form with material components
if ( is.function(onChange) ) {
onChange(custom.cvalue);
}
input.onChange(custom.cvalue);
}
return (
<SelectField
{...input}
{...custom}
fullWidth={true}
children={children}
floatingLabelText={label}
errorText={touched && error}
onChange={(event, index, value) => {
if ( is.function(onChange) ) { // and custom onChange for f....g ....
value = onChange(value);
}
input.onChange(value);
}}/>
)
}
then in template
its can be way to make form of editing existing entity ....
<Field
name="study"
label="Studies"
component={ FormSelect }
cvalue={this.state.study.id}
onChange={value => {
this.setState({study: _.find(studies, {id: value})||{id: 0}});
return value;
}}>
{studies.map( (study, key) => ( <MenuItem key={key} value={study.id} primaryText={study.officialTitle} /> ))}
</Field>

Resources