I want to set a city name field automatically after a zip code selection. I guess i could fire redux-form/CHANGE for city field myself but it feels kind of wrong since there is no api method for this.
What is the proper way?
That's an async lookup?
No. I already do have the city value. I just want to set it when zip code is selected for better ux.
Isn't this a common use case? I mean the redux-form holds the input state, so I think there should be a way to modify the state via an action too.
Your options, from least desirable to most (in my opinion):
CHANGE yourself.import {actionCreators} from 'redux-form';
...
dispatch(actionCreators.change('addressForm', 'city', 'cityValue'));
city.onChange()Or, if you're in your component, you can just call this.props.fields.city.onChange('cityValue') to dispatch the action. This is nicer than the manual dispatch because it has the form name and field name in it already.
If you have the zip-to-city map locally on the client, the proper way to set a field value when another field value changes is with the normalize() API.
Normalizer looks a bit misused to me in this case. The second option is the easiest and covers the problem completely. I'll go with it. Thank you.
Hey @erikras calling fields.xxx.onChange(value) doesn't set value of <input>, and doesn't trigger onChange of <form>.
How can I set the value of <input> just via field.xxx?
@fritx this.props.fields.xxx.onChange(value) sets the value in the store, which, on next render, will be the value of this.props.fields.xxx.value, which you should be passing to your <input>.
As far as I know, there is no onChange on <form>. Correct me if I'm wrong?
Form components allow listening for changes by setting a callback to the onChange prop.
-- https://facebook.github.io/react/docs/forms.html#interactive-props
onChange of <form> is available in both regular HTML and react
And my app is working with:
<form onChange={(e)=>{
const { name, value } = e.target
}}></form>
I will try for more and reply you soon once I'm free. Thanks.
Huh! Interesting. I've never come across that in my 20+ years of web dev. You learn something every day. :smile:
But yes, redux-form does call event.stopPropagation() on the input's onChange event, so that would probably make the onChange on <form> not fire.
Haha, great!
But what could I do with the <form> onChange if I need it in redux-form? @erikras
I just need to subscribe fields change inside the component.
Well... maybe something like this?
handleFormChange(event) {
// do whatever you were doing
}
makeOnChange(field) {
return (event) => {
field.onChange(event);
this.handleFormChange(event);
};
}
render() {
const {fields: {firstName, lastName}} = this.props;
return (<form>
<input type="text" {...firstName} onChange={this.makeOnChange(firstName)}/>
<input type="text" {...lastName} onChange={this.makeOnChange(lastName)}/>
</form>);
}
By putting the onChange prop after the destructured field prop, it will override the onChange that was destructured in with the new function.
Ah.. It's a bit annoying :/
Btw, why does redux-form have to stop propagation?
https://facebook.github.io/react/docs/forms.html#uncontrolled-components
Finally I tried this way:
<form onChange={(e)=>this.onFormChange(e)}>
<input type="radio" name="xxx" defaultChecked={fieldXXX.value} value="0" />
<input type="radio" name="xxx" defaultChecked={fieldXXX.value} value="1" />
<select name="xxx" value={fieldXXX.value}>
onFormChange(e) {
const { name, value } = e.target
if (!name) return
fields[name].onChange(value)
//... do some saving
}
Cuz this form is special, I have to use one single form.onChange capture.
And I'm looking for any better way to do it.
In other normal forms, I'd like to do it the redux-form way. ;)
@fritx Do you use form state values during your saving after fields[name].onChange(value)? I have the problem that the state is not immediately changed after calling field.onChange
@erikras Is it possible to be notified on a change of one field and get all form state values? because in your example if handleFormChange(event) is called the form state may not be updated with the new value. Or how can i be notified when one or more values of a specific set of fields in the state was modified?
@kromit no I didn't use state in form.onChange
I need something similar to this:
My form is inside a component that receives props. I would like to set the default value of an input field to something passed from the props (it's a new/edit form). I'm able to do so by doing this.props.fields.name.value = this.props.name . The field is updated correctly but then, when it's time to validate, the values passed to the validate function contain an undefined value for name. If I focus then remove focus from my field, this gets fixed.
What do you guys suggest here?
@zxiest you should not modify props from inside a component! In your case only the prop is modified but not the state. There is initialValues prop to initialize the state.
@kromit the problem with initialValues is that it's outside my class. I need to pass initialValues to my form with values coming into props (it would be great if we can pass it like below on the form)
render() {
const { fields: { name }, handleSubmit } = this.props;
const initialValues = {
name: this.props.name
}
return (
<form className='new-step' onSubmit={handleSubmit(this.onSubmit.bind(this))}
initialValues={initialValues}>
<div className='body'>
<div className="form-group">
<input placeholder='Name' className='form-control' {...name} />
<div className='text-help'>
{name.touched ? name.error : '' }
</div>
</div>
</form>
)
}
@zxiest i'm having the same issue here any ideas ?
@zxiest, the same problem. This definitely needs some explanations or workarounds.
Same problem!
@safouman @alyrik I found a workaround but it's not worth the effort. I ended up recoding that page. It's easier to have my own validations than to go through redux-form when I have complicated, custom stuff.
Same problem!
Facing same problem. when ever i create form how do i pass props value as default value to form input?
in reducer we set the initial
import { FACEBOOKED_CLICK, CHANGE_NAME } from 'somewhere';
const initialState = {
facebookIsChecked: false,
twitterIsChecked: false,
changeName: null,
};
export default function (state = initialState, action = null) {
switch (action.type) {
case FACEBOOKED_CLICK :
return Object.assign({}, state, {
facebookIsChecked: action.payload,
});
case CHANGE_NAME :
return Object.assign({}, state, {
changeName: action.payload,
});
default : return state;
}
}
Same problem..
I'm working on calculating currency exchange calculator with inputs.
i tried to send calculated receive amount as props after changing send amount,
but it makes my whole application horribly slow.
i want to use redux-form because i want to check form or field is invalid, touched, on so on.
but my whole efforts of 7 hour have failed ... any updates?
i think that reducer.plugin() is the one i'm looking for..
getting access to reducer of redux-form
export const transferFormPlugin = (state, action) => {
if (action.type === 'redux-form/CHANGE' && action.meta && action.meta.form === 'transfer' && action.meta.field) {
if (action.meta.field === 'sendAmount') {
// divide by 10 is dummy calculation for exchange
return state.setIn(['values', 'receiveAmount'], action.payload / 10);
} else if (action.meta.field === 'receiveAmount') {
return state.setIn(['values', 'sendAmount'], action.payload * 10);
}
}
return state;
};
then i applied this function (which is called plugin in api document) as below
form: formReducer.plugin({
transfer: transferFormPlugin }),...
or if you're using redux-saga
watch redux-form/CHANGE by using take(pattern: function)
then modify form state by
import { change } from 'redux-form/immutable';
...
yield put(change('transfer', 'sendAmount', foo));
i think this is better than above one, because you have full access to overall state using yield select()
Hi all I know this issue is closed but I have spent a couple evenings on this and I am getting nowhere. In Redux Form 6 what is the best way for field A to set the value of Field B?
I have tried this.props.dispatch(change(formname,fieldname,somevalue)); gazillion times and ways and although it doesn't error the target field just wont change in the DOM or in the values argument passed to the sync validation function.
Also what about Field B reading the current (not initial) value of Field A? Although after hours of converting all of my fields to Components from stateless function I can now get refs to them but can't access the field value.
Any help would be great...I am at the point where JQuery will be my obi-wan but I really want to do this the redux-form way...this should not be so difficult, right?
Hi @jvchappell! Perhaps you should use a stronger Jedi, like Luke Skywalker?
See this demo: http://www.webpackbin.com/Ek208fMOM
@jvchappell you have to be inside of your form component. Then just call this.props.change("myfield“, value)
Thanks @kromit and @gustavohenke for answering so quickly! My two related fields are in a separate component (so I can re-use them) and passing the parent form component's this.props.change down the line so I could get to it worked! I had spent HOURS trying to get that sorted. Thanks again!
I am trying to solve the same problem.
I have 2 fields on the form currency1 and equivalent USD currency in cents.
I need to show values of both currency formatted.
As well as user is allowed to change either of the input field.
The both the currencies values need to be in sync tho based on the currency conversion.
In the end I store the USD currency in cents.
How can I make sure if user changes USD currency the other currency1 is updated and vice versa, but in the end I have the final value of USD currency in cents as value to be stored?
Hi @chetangautam,
old comment, but in case you still have this problem, here's an example of form which behaves the way you described:
https://codesandbox.io/s/wjJVPgYRw
Hope it can help you or others in the same situation.
For anyone reading this, its no longer
import { actionCreators } from 'redux-form';
but
import { change } from 'redux-form';
In order to programmatically change a field from outside the form component
Hello everyone,
I'm trying to use a <Toggle /> instead of checkbox inside my redux-form. But although I'm using change it still doesn't make any change in form state. This is my code:
import { reduxForm, change, Field } from 'redux-form';
const renderToggle = () => {
return (
<Toggle
onToggle={(even, isInputChecked) => {
change('myReduxForm', 'toggleComp', isInputChecked);
}}
/>
);
};
And inside my redux-form I just have:
<Field
component={renderToggle}
name="toggleComp"
type="checkbox"
/>
At the bottom:
export default reduxForm({
form: 'myReduxForm'
})(injectIntl(MyClassComponent));
For a project I am working on, I managed to update the application state by dispatching the change action, like this :
import React, { Component } from 'react';
import { reduxForm, change } from 'redux-form';
import { connect } from 'react-redux';
// THIS function will be used at the bottom as connection to redux
// 'change: .... ' is connected to MyForm as a prop !
const mapDispatchToProps = dispatch => ({
change: (field, value) =>
dispatch(change('formName', field, value)),
});
class MyForm extends Component {
constructor(args) {
super(args);
this.myCustomFunction= this.myCustomFunction.bind(this);
}
myCustomFunction() {
// manipulate data, pass anything to the function, do your business
this.props.change('fieldName', newValue); // THIS triggers the dispatch, it's the connected prop
}
render() {
// call myCustomFunction whenever needed...
return (
<form name="formName">
// <Fields /> here
</form>
);
}
}
// THIS is the actual connection to redux + redux-form
export default connect(mapDispatchToProps)(
reduxForm({ form: 'formName' })(injectIntl(MyForm ))
);
This code properly connects the programmatical "change" I trigger to redux-form and changes the values in the state accordingly.
On my part I still struggle though with a color picker component which does not update its value when the application state changes...
I stumbled across a similar problem: Every time the value of a form field another form field should update dependent on that form fields value.
I used formValueSelector for that case.
Probable use cases:
Because the example provided for formValueSelector didn't include using the form with different names I created this relatively small full solution:
// SomeForm.jsx:
import React from 'react';
import {connect} from 'react-redux';
import {Field, reduxForm, formValueSelector} from 'redux-form';
let SomeComponentUseFirstFieldValue = ({firstFieldValue, ...props}) => {
// do something with 'firstFieldValue'
return (...);
}
const mapStateToPropsForSomeComponentUseFirstFieldValue = (state, initalProps) => {
// Use 'initalProps.firstFieldValue' to retrieve something from state if needed.
return {...};
}
const mapDispatchToPropsForSomeComponentUseFirstFieldValue = (dispatch, ownProps) => {
// Use 'ownProps.firstFieldValue' to retrieve with dispatch
}
SomeComponentUseFirstFieldValue = connect(
mapStateToPropsForSomeComponentUseFirstFieldValue,
mapDispatchToPropsForSomeComponentUseFirstFieldValue
)(SomeComponentUseFirstFieldValue);
let SomeForm = ({handleSubmit, firstFieldValue, ...props}) => (
<form onSubmit={handleSubmit}>
<Field
name='first'
component='input'
type='text'
/>
<Field
name='second'
component={SomeComponentUseFirstFieldValue}
firstFieldValue={firstFieldValue} // Pass 'firstFieldValue' to Field component.
/>
{firstFieldValue &&
<Field
... // Conditional show Field.
/>
}
</form>
);
SomeForm = reduxForm({
// options
})(SomeForm);
const mapStateToPropsForSomeForm = (state, initialProps) => ({
firstFieldValue: (formValueSelector(initialProps.name))(state, 'first')
});
SomeForm = connect(
mapStateToPropsForSomeForm
)(SomeForm);
export default SomeForm;
// AnotherComponent.jsx:
import React from 'react';
import SomeForm from 'SomeForm';
const AnotherComponent = (props) => (
<SomeForm
name='form1'
initialValues={...}
...
/>
)
@fabioespinosa @erikras
import {actionCreators} from 'redux-form';
actionCreators doesn't exist in redux-form
Ah
NOT CORRECT
import { actionCreators } from 'redux-form';
import { change } from 'redux-form';
and just use
dispatch(change('addressForm', 'city', 'cityValue')); *removed actionCreators.
@nerfologist:
sandbox example you sent is wonderfull. Its helpful and very concise.
https://codesandbox.io/s/wjJVPgYRw
But how can we use the same for FieldArray. I am passing change as parameter with FieldArray but it doest work.
<Field
name={`${member}.firstName`}
type="text"
component="input"
onChange={(event, newValue, previousValue) => {
change(`${member}.lastName`,newValue);
}}
label="First Name"/>
Your options, from least desirable to most (in my opinion):
Dispatch
CHANGEyourself.import {actionCreators} from 'redux-form'; ... dispatch(actionCreators.change('addressForm', 'city', 'cityValue'));Call
city.onChange()Or, if you're in your component, you can just call
this.props.fields.city.onChange('cityValue')to dispatch the action. This is nicer than the manual dispatch because it has the form name and field name in it already.Normalizer
If you have the zip-to-city map locally on the client, the proper way to set a field value when another field value changes is with the
normalize()API.
I tried the normalize approach: I placed the normalize function on the city field, but the issue seems to be that, making new selection on the zip code field would not trigger the normalize function on the city field. Did I misunderstand how I'm supposed to do this normalize approach?
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
Your options, from least desirable to most (in my opinion):
Dispatch
CHANGEyourself.Call
city.onChange()Or, if you're in your component, you can just call
this.props.fields.city.onChange('cityValue')to dispatch the action. This is nicer than the manual dispatch because it has the form name and field name in it already.Normalizer
If you have the zip-to-city map locally on the client, the proper way to set a field value when another field value changes is with the
normalize()API.