I'm creating a customised component for my form.
What I want: after I click a certain location, in my onClick handler, I can set the corresponding value for the form field.
How to do that?
My current solution:
_onClick(value, evt) {
const {field, dispatch} = this.props
if(dispatch){
dispatch({type: "redux-form/CHANGE", field: field.name, value: value, touch: false, form: field.form})
}
}
it doesn't work yet.. but even if it works, I feel this is kind of hack.
Any better solution?
Issue resolved after taking a look at this one: http://erikras.github.io/redux-form/#/faq/custom-component?_k=qnjmi9
@flyfy1 DONOT dispatch redux-form/CHANGE
programmatically.
Yes you can use this.fields.xxx.onChange(value)
to change a value.
This might help you: https://github.com/erikras/redux-form/issues/152
You can set value for a field by do this:
First, in the container component, pass changeFieldValue()
function as a property via mapDispatchToProps
parameter of reduxForm()
, which dispatches the action created from the action creator change()
:
// CustomFormContainer.jsx
import {
reduxForm,
change // The action creator
} from 'redux-form'
// The presentational component
import CustomForm from './CustomForm.jsx'
const form = 'your-form-name'
const fields = [ 'field-foo', 'field-bar', 'field-baz' ]
const CustomFormContainer = reduxForm({
form,
fields
},
/* mapStateToProps = */ undefined,
/* mapDispatchToProps = */ function(dispatch) {
return {
// This will be passed as a property to the presentational component
changeFieldValue: function(field, value) {
dispatch(change(form, field, value))
}
}
})(CustomForm)
export default CustomFormContainer
Then, in ./CustomForm.jsx
file, your can do:
this.props.changeFieldValue('field-baz', 'my-value')
@rockallite, thanks, that really helped! I was actually able to get it to work by passing changeFieldValue into bindActionCreators in the more usual redux style - I just imported change from redux-form using the changeFieldValue alias.
import { bindActionCreators } from 'redux';
import { reduxForm, reset, change as changeFieldValue } from 'redux-form';
import { addFurniture } from '../actions/furniture.action.js';
// some import statements omitted here for brevity
class AddFurnitureForm extends Component {
render() {
const { fields: {
itemName, price, description, url, size, color
}, handleSubmit, } = this.props;
return (
<form onSubmit={ handleSubmit(this.props.addFurniture.bind(null, this.props.roomSelected)) }>
<Input s={4} placeholder="Size (centimeters)" { ...size } />
<Input s={4} placeholder="Primary color" { ...color } />
<ColorInput s={4} action={ colorObj => this.props.changeFieldValue('AddFurnitureForm', 'color', colorObj.hex) } />
<RaisedButton type="submit" label="submit"/>
</form>
);
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ addFurniture, changeFieldValue }, dispatch);
}
export default reduxForm({
form: 'AddFurnitureForm',
fields: ['itemName', 'price', 'description', 'url', 'size', 'color'],
}, state => ({ roomSelected: state.roomSelected }), mapDispatchToProps)(AddFurnitureForm);
For future reference, the new way to do this in version 6 is using this.props.change(field_name, value). See the docs.
Hey, is there a way to change multiple fields? One change event with many fields instead many events with one field.
this.props.change(field,value) does not work for me. I get a response back that looks alright but the value doesn't change and touch is still false.
this.props.change('salary.max_salary', undefined);
returns
meta:
Object
field:"salary.max_salary"
form:"JobsForm"
persistentSubmitErrors:false
touch:false
__proto__
Object
payload:undefined
type:"redux-form/CHANGE"
__proto__
My goal is to set the field to undefined if the user wants to set the maxSalary to none
@StRibbon you ever figure this out? I want to be able to have a button that sets a hidden field value.
@ericdfields I did! Thank you for following up.
@StRibbon heh, I originally asked because I wanted a similar solution :) I got something that works though.
I wanted a button to set _dirty: true
on a nested field. I wound up with the following:
// Stateless Destroy button
const DestroyBtn = ({input,label = 'Destroy'}) =>
<button type="button" onClick={() => input.onChange(true)}>{label}</button>
// inside a FieldArray
{fields.map((member, index) => {
if (fields.get(index)._destroy) {
return false
}
return(
<li key={index}>
<Field name={`${member}._destroy`} component={DestroyBtn} label={'Remove Fax Number'} />
<Field
name={`${member}.title`}
type="text"
component={renderField}
label="Title"/>
<Field
name={`${member}.value`}
type="text"
component={renderField}
label="Value"/>
</li>
)
}
This worked, but I had an unexpected behavior where the field wouldn't remove itself from view (wasn't getting re-rendered and passing the _destroy
conditional). I had to set prop touchOnChange: true
on my reduxForm HOC.
this.props.change(field_name, value)
not selecting select
field option
@StRibbon Don't mean to bother you, but would be curious to hear how you fed a value of "undefined" into the change action. I'm trying to do the same thing to set a field value, but any time I use "undefined" as the target value, nothing changes. If I set any other value (strings, numbers, etc.) in there it works instantly, but undefined gets me no change. My change statement looks like:
this.props.change('study', undefined);
@threepears, just like this
this.props.dispatch(change('JobsForm', 'salary.max_salary', undefined));
you need to send 3 arguments.
@StRibbon : Unfortunately, that doesn't seem to work for me. I tried both using this.props.dispatch
with three arguments and this.props.change
with both three and two arguments directly.....any time I use "undefined" as the value, it doesn't work. I ended up using "null", which works fine in all cases, but still can't figure out why "undefined" is not accepted as a value. Thanks for getting back to me, though!
What if you're dealing with sub-components of your form which aren't the HOC itself and thus don't have access to the this.props.change
function? Can you map it somewhere or does one have to pass it all the way down as props?
@fcfl you can import these action creators from redux-form
, but you'll have to pass the form name as the first argument.
Thanks @timhwang21 o/
Hi, is there a way to set initial field value without triggering onchange
action because it triggers re-rendering of almost entire form (in my case)
@threepears I think it has to do with this:
The function won't set a value if the value is undefined, which makes some sense when you consider that JS function parameters that are not used are undefined. That is a behaviour you might not want. Not to mention that the undefined value is intended only to be used for something that has never been defined (hence the name) and all possible object attributes are undefined.
However, it is something that could have been stated in the documentation.
I tried all the proposed solutions unsuccessfully. It would only change the field values if I refreshed the page, but not when I changed pages through clicking links with React Router. I ended up just hacking the dom in componentDidMount
componentDidMount() {
// Hack since `changeFieldValue` to update the field values does not work
document.getElementById('wallet-address').value = this.props.metaMask.account;
}
componentWillReceiveProps(nextProps) {
console.log('nextProps: ', nextProps.metaMask.account);
console.log('dispatch: ', this.props.dispatch);
if (nextProps.metaMask.account && nextProps.metaMask.account !== this.props.metaMask.account) {
// this.props.dispatch(changeFieldValue('login', 'walletAddress', nextProps.metaMask.account));
this.props.change('walletAddress', nextProps.metaMask.account);
}
}
...
<Field
name="walletAddress"
type="text"
id="wallet-address"
className="wallet-address"
label="Wallet Address"
component="input"
placeholder="Wallet Address"
/>
...
// Obtain necessary Redux state
const mapStateToProps = (state) => ({
login: state.login
});
const mapDispatchToProps = (dispatch) => {
return {
handleLoginRequest: ({ walletAddress }) => {
return dispatch(loginRequestAction(walletAddress));
}
}
};
// Connect component to Redux
// Attach `login` state to component `props`
// Attach `loginRequest` Action to component `props`
const connected = withRouter(connect(
mapStateToProps,
mapDispatchToProps
)(Login));
// Connect the connected component to Redux Form with Unique Form Name
const createReduxForm = reduxForm({
form: 'login',
enableReinitialize : true
});
const LoginForm = createReduxForm(connected);
export default LoginForm;
Are there any updates on this? In my app the distinction between "null" and "undefined" is important for validation - some fields will be nullable but we need the user to explicitly "null" out the field to make it valid, and in other circumstances we want to invalidate the field manually by setting it back to undefined through dispatching an action. Using input.change()
or change()
with undefined does not achieve this.
It would be really nice if there was a delete()
action I can dispatch to just delete that field value from the form without unregistering the field.
@amized Is there some other value that you can use as "not valid" instead of undefined
? e.g. in my current project I use an empty string to reset the value to a non valid state.
I actually solved the problem with the clearFields()
action, which does exactly what I want. This was only released in v7.2.0.
Also struggling with this. Some good examples above but for V6 using this.props.change(), it's not clear how to use this. Where are we even calling this prop? Would like to see a complete example.
Working on this problem now, if I find the solution I'll post a complete example.
Same issue as NathanCH. I would like to invoke props.onChange in response to clicking on a checkBox. How is this done? So far the examples have been unintuitive.
@degamer106, I actually found this to be an anti-pattern for my use-case. Instead of triggering a change on the form directly, trigger a change in your application state. Your initial values will update to reflect this change assuming your initial values are set from application state.
This may mean moving additional state to your store.
@NathanCH I was able to figure out my use case from the comments in this thread: https://github.com/erikras/redux-form/issues/1500
To summarize, you need to add the desired form fields as props to your component by calling formValueSelector in your react-redux connect() method:
componentWillUpdate(nextProps) {
if (nextProps.exempt !== this.props.exempt) {
this.handleExempt(nextProps.exempt);
} else if (nextProps.marriedFilingSingle !== this.props.marriedFilingSingle) {
this.handleMarriedFilingSingle(nextProps.marriedFilingSingle);
}
}
// ....
const Form = reduxForm({
form: 'federalTax',
initialValues: {
addlAmount: '5.00',
allowances: '1',
exempt: true,
marriedFilingSingle: false,
maritalStatus: 'M',
},
})(FederalTaxFormModal);
const formSelector = formValueSelector('federalTax');
const mapStateToProps = state => ({
exempt: formSelector(state, 'exempt'),
marriedFilingSingle: formSelector(state, 'marriedFilingSingle'),
});
export default connect(mapStateToProps, null)(Form);
@nickbarry Is there documentation on how to use change
in stateless components?
Is there any solution for this issue even for me this doesn't work when I call this.props.change('fieldName', undefined)
(change func passed from reduxForm to myFormComponent)
@aqumus your should pass the form name as first argument of change function:
this.props.change('formName', 'fieldName', undefined)
@aqumus your should pass the form name as first argument of change function:
this.props.change('formName', 'fieldName', undefined)
The 'formName'
argument is needed if you import the change function from the package directly, not if you got it as a prop from the reduxForm()
HOC, as @aqumus described.
For anybody struggling with a similar issue, try setting anything other than undefined
for the value (e.g. null
or ''
).
@aqumus can you help me to change/ mask the value once i tabout/focusout the filed?
Example: i need to replace the number entered in the field with ** after tabout.
i tried using this.props.change('fieldname', 'new_value'); it is updating the field value but not reflecting on UI.
For me, nothing works. I am trying to set the value other than null or undefined, but it doesn't work.
For future reference, the new way to do this in version 6 is using this.props.change(field_name, value). See the docs.
this is very best
but I want to update 4 fields value
on changing on-field value.
in such cases, i needed to call this.props.onChange('fieldName', value) for 4 times, resulting 4 time re-rending of the form
how I can achieve this in a single action?
For future reference, the new way to do this in version 6 is using this.props.change(field_name, value). See the docs.
this is very best
but I want to update 4 fields value
on changing on-field value.in such cases, i needed to call this.props.onChange('fieldName', value) for 4 times, resulting 4 time re-rending of the form
how I can achieve this in a single action?
In my experience calling a couple of changes didn't have a big performance impact, but in case you really need it to be one action you can:
FormSection
and update the entire FormSection
via change
(see details in docs)initialize
- spread all the values from the current form (you might need a selector for that), update that object with the values you want to change and pass that object to the initialize
function (see details in docs)P.S. the docs I linked are for version 8, check the docs for the version your using, but if the initialize
action is pretty old and should work, not sure about calling change on form sections.
Most helpful comment
For future reference, the new way to do this in version 6 is using this.props.change(field_name, value). See the docs.