Set the value of a form based on state in React

Viewed 2300

Using Formik for validating some fields, if a state value is true I want that the value of a fields to be copied to the value of another one.

For example, value of mainAddress to be copied to address.

There is a state variable, setAddress which is set on false but it can be changed to true when a checkbox is clicked.

When this variable is set on true I want that the value of mainAddress to be copied to address

This is the code that works fine without copying that value:

import React from 'react';
import { Formik, Form, Field } from 'formik';
import { Input, Button, Label, Grid } from 'semantic-ui-react';
import * as Yup from 'yup';
import { Creators } from '../../../actions';
import './CreateCompanyForm.scss';

class CreateCompanyForm extends React.PureComponent {
  constructor(props) {
    super(props);

    this.state = { // state variables 
      address: '',
      mainAddress: '',
      setAddress: false,
    };
  }

  handleSubmit = values => {
    // create company
  };

  toggleAddress = () => { // it toggles the value of setAddress
    this.setState(prevState => ({
      setAddress: !prevState.setAddress,
    }));
  };

  render() {
    const initialValues = { // the address and mainAddress are set to '' at the start
      address: '',
      mainAddress: '',
    };
    const validationSchema = Yup.object({
      address: Yup.string().required('error'),
      mainAddress: Yup.string().required('error'),
    });
    return (
      <>
        <Button type="submit" form="amazing"> // button for submit
          Create company
        </Button>

        <Formik
          htmlFor="amazing"
          initialValues={initialValues}
          validationSchema={validationSchema}
          onSubmit={values => this.handleSubmit(values)}>
          {({ values, errors, touched, setValues, setFieldValue }) => (
            <Form id="amazing">
              <Grid>
                <Grid.Column> // mainAddress value
                  <Label>Main Address</Label>
                  <Field name="mainAddress" as={Input} />
                </Grid.Column>

                <Grid.Column> // address value
                  <Label>Address</Label>
                  <Field name="address" as={Input} />
                  <div>
                    {this.state.setAddress // here is how I've tried to set that value
                      ? values.address.setFieldValue(values.mainAddress)
                      : console.log('nope')}
                    {touched.address && errors.address ? errors.address : null}
                  </div>
                </Grid.Column>
              </Grid>
              <Checkbox
                label="Use same address"
                onClick={() => this.toggleAddress()}
              />
            </Form>
          )}
        </Formik>
      </>
    );
  }
}

So I've tried more ways to solve it but without success. Now in the code it is:

 {this.state.setAddress
     ? values.address.setFieldValue(values.mainAddress)
     : console.log('nope')}

Other one was: (this.state.setAddress ? values.address = values.mainAddress)

None of them work. Is it possible to get the value from values.mainAddress and copy it to values.address? Or to its input?

2 Answers

You can rewrite the Field component for address accordingly.

<Field name="address">
 {({
    field, // { name, value, onChange, onBlur }
 }) => {
   values.address = values.mainAddress;
   return (
     <div>
        <input
           {...field}
           type="text"
           placeholder="Address"
         />
      </div>
    );
  }}
</Field>

Here we are setting the value of address field to values.mainAddress if setAdress checkbox is checked else we let formik value to fill it.

Here is the working codesandbox code - https://codesandbox.io/s/fervent-tereshkova-sro93?file=/index.js

Formik also provides values object you could use that for updating address value same as mainAddress. Just provide name attribute to both input fields then assign like this - props.values.address = {...props.values.mainAddress}

Related