Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set Value for a field via code? #369

Closed
flyfy1 opened this issue Dec 2, 2015 · 35 comments
Closed

Set Value for a field via code? #369

flyfy1 opened this issue Dec 2, 2015 · 35 comments

Comments

@flyfy1
Copy link

flyfy1 commented Dec 2, 2015

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?

@flyfy1
Copy link
Author

flyfy1 commented Dec 2, 2015

Issue resolved after taking a look at this one: http://erikras.github.io/redux-form/#/faq/custom-component?_k=qnjmi9

@flyfy1 flyfy1 closed this as completed Dec 2, 2015
@xcatliu
Copy link

xcatliu commented Dec 2, 2015

@flyfy1 DONOT dispatch redux-form/CHANGE programmatically.
Yes you can use this.fields.xxx.onChange(value) to change a value.
This might help you: #152

@rockallite
Copy link

rockallite commented May 4, 2016

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')

@nicogreenarry
Copy link
Contributor

@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);

@nicogreenarry
Copy link
Contributor

For future reference, the new way to do this in version 6 is using this.props.change(field_name, value). See the docs.

@MistyKuu
Copy link

Hey, is there a way to change multiple fields? One change event with many fields instead many events with one field.

@StRibbon
Copy link

StRibbon commented Feb 9, 2017

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

@ericdfields
Copy link

@StRibbon you ever figure this out? I want to be able to have a button that sets a hidden field value.

@StRibbon
Copy link

StRibbon commented Mar 1, 2017

@ericdfields I did! Thank you for following up.

@ericdfields
Copy link

ericdfields commented Mar 1, 2017

@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.

@vedran-milic
Copy link

vedran-milic commented Jun 1, 2017

this.props.change(field_name, value) not selecting select field option

@threepears
Copy link

@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);

@StRibbon
Copy link

StRibbon commented Jun 8, 2017

@threepears, just like this

this.props.dispatch(change('JobsForm', 'salary.max_salary', undefined));

you need to send 3 arguments.

@threepears
Copy link

@StRibbon : Unfortunately, that doesn't seem to work for me. I tried both using this.props.dispatch with three arguments and this.props.changewith 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!

@fcfl
Copy link

fcfl commented Jun 21, 2017

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?

@timhwang21
Copy link
Contributor

@fcfl you can import these action creators from redux-form, but you'll have to pass the form name as the first argument.

@fcfl
Copy link

fcfl commented Jun 21, 2017

Thanks @timhwang21 o/

@kristinalyba
Copy link

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)

@pero5ar
Copy link

pero5ar commented Sep 29, 2017

@threepears I think it has to do with this:

https://github.com/erikras/redux-form/blob/08375392ea901ca315aaf7f77b4d6e676bb6b9ec/src/actions.js#L240

https://github.com/erikras/redux-form/blob/08375392ea901ca315aaf7f77b4d6e676bb6b9ec/src/createReducer.js#L220

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.

@ltfschoen
Copy link
Contributor

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;

@amized
Copy link

amized commented Mar 27, 2018

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.

@pero5ar
Copy link

pero5ar commented Mar 28, 2018

@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.

@amized
Copy link

amized commented Mar 28, 2018

I actually solved the problem with the clearFields() action, which does exactly what I want. This was only released in v7.2.0.

@nathan-charrois
Copy link

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.

@degamer106
Copy link

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.

@nathan-charrois
Copy link

@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.

@degamer106
Copy link

degamer106 commented Apr 25, 2018

@NathanCH I was able to figure out my use case from the comments in this thread: #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);

@janosh
Copy link

janosh commented May 24, 2018

@NickBarry Is there documentation on how to use change in stateless components?

@aqumus
Copy link

aqumus commented Oct 21, 2018

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)

@mabzzz
Copy link

mabzzz commented May 16, 2019

@aqumus your should pass the form name as first argument of change function:
this.props.change('formName', 'fieldName', undefined)

@pero5ar
Copy link

pero5ar commented Jun 4, 2019

@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 '').

@vadapallihemalatha
Copy link

vadapallihemalatha commented Jul 12, 2019

@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.

@norayr93
Copy link

For me, nothing works. I am trying to set the value other than null or undefined, but it doesn't work.

@Dhirajbhujbal
Copy link

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?

@pero5ar
Copy link

pero5ar commented Jul 14, 2020

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:

  1. group those values into a FormSection and update the entire FormSection via change (see details in docs)
  2. update the entire form via 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests