Brady Edgar
Brady Edgar

Reputation: 543

How to pre populate an "redux form's" input fields after form has already rendered

I am using redux form for a React app I am working on, the redux form version is V.6. I am also using a wizard style form(so after each fieldset is completed the user can click a "proceed to next step" button to fill out the next section of the form). So what I want to happen is that when the user fills out the "shipping and delivery" fieldset, I want the "billing and payment" feildset(the next feildset in the form) to auto fill with the values entered in the "shipping and delivery" fieldset. They both are identical fieldsets.

Unfortunately it seems like I will not be able to use the intialValues prop since the form will already be rendered when the users enters their values into the form. I also run into issues setting values in the redux form manually in the backend as redux form doesn't seem to be a fan of this method. I can set the value manually, but then I can no longer update it with the input field

In hindsight I wish I built the form more like the example wizard form on the redux form webpage where each "feildset" is actually its own form, but as of right now I can't go back and make those changes, so it all needs to stay as one big form.

If anyones has any advice or opinions please let me know!

The form dumbed down looks like this:

<form>
    <ShippingAndDelivery
        checkFieldsetProgress={this.checkFieldsetProgress}
        handleUpdatingDeliveryType={handleUpdatingDeliveryType}
        availableShippingTypes={availableShippingTypes}
        shippingType={shippingType}
        handleShippingRequest={handleShippingRequest}
        recieveShippingError={recieveShippingError}
        shippingError={shippingError}
    />
    <BillingAndPayment 
        checkFieldsetProgress={this.checkFieldsetProgress}    
        handlePopulateBillingAddress={handlePopulateBillingAddress}
        promoCodeValue={promoCode}
    />
</form>

It is also in an es6 class so i can mess with states and everything if I need to.

The fieldset components(so ShippingAndDelivery and BillingAndPayment) use the and component like this:

class shippingAndDelivery extends React.Component {
   render () {
       const {
           whatEverPropsNeeded
       } = this.props;
       return (
           <div>
               <Fields
                   names={[
                       'address_shipping',
                       'email_shipping'
                   ]}
                   component={RenderedFields}
                   whatEverPropsNeeded={whatEverPropsNeeded}
                />
           </div>
       )
   }
}

const RenderedFields = ( fields ) => (
<div className={style.container} onChange={fields.updateProgress(fields)}>
    <Col md={8}>
        <fieldset>
            <div className={style.title}>
                <p>Shipping Address</p>
            </div>
            <Col md={12}>
                <BasicInput
                    input={fields.email_shipping.input}
                    meta={fields.email_shipping.meta}
                    disabled={false}
                    placeholder="Email Address"
                />
            </Col>
            <Col md={12}>
                <BasicInput
                    input={fields.address_shipping.input}
                    meta={fields.address_shipping.meta}
                    disabled={false}
                    placeholder="Address Line 1"
                />
            </Col>
            </div>
        </fieldset>
</div>
);

Upvotes: 3

Views: 2286

Answers (1)

jakee
jakee

Reputation: 18556

You can use the enableReinitialize prop of reduxForm to re-initialize the form any time initialValues changes, thus enabling you populate the downstream fields with values from the upstream.

I would use formValueSelector to extract the values from the redux store and set them to initialValues. Use the keepDirtyOnReinitialize prop to make sure reinitialization does not overwrite your unsaved changes to the shipping address. Example:

const selector = formValueSelector('MyFormName')

const mapStateToProps = reducers => {
  // obtain shipping address values from the redux store
  const {
    address,
    addressOptional,
    city,
    zipCode,
    country
  } = selector(reducers, 'shipping')

  return {
    initialValues: {
      // shipping address is empty initially
      shipping: {
        address: '',
        addressOptional: '',
        city: '',
        zipCode: '',
        country: ''
      },
      // billing address initial values are changed any time
      // the shipping address values are changed
      billing: {
        address,
        addressOptional,
        city,
        zipCode,
        country
      }
    }
  }
}

@connect(mapStateToProps)
@reduxForm({
  form: 'MyFormName',
  // reinitialize the form every time initialValues change
  enableReinitialize: true,
  // make sure dirty fields (those the user has already edited)
  // are not overwritten by reinitialization
  keepDirtyOnReinitialize: true
})
class MyFormContainer extends MyFormComponent {}

Hope this helps!

Upvotes: 3

Related Questions