4
votes

I've been trying to rewrite my beginner form in React to use Formik. I've gotten to the state that the form is being rendered, however, for some reason, I can't update the fields. It's clear that I made a mistake somewhere that prevents Formik from updating the state. What am I missing?

An example form component:

export const TextBox: React.SFC<FieldProps<any> & CustomFormElementProps> = ({
    field, // { name, value, onChange, onBlur }
    form: { touched, errors }, 
    loading,
    ...props
}) => (
        <div className="row form-group" key={field.name}>
            <label className="col-sm-2 control-label">
                <ReactPlaceholder showLoadingAnimation ready={!loading} type="text" rows={1} className="control-label">
                    {props.label}
                </ReactPlaceholder>
            </label>
            <div className="col-sm-10">
                <ReactPlaceholder showLoadingAnimation ready={!loading} type="text" rows={1} className="form-control">
                    <input type="text"
                        disabled={props.disabled}
                        className="form-control"
                        id={field.name}
                        onChange={field.onChange}
                        onBlur={field.onBlur} {...props} />
                    {touched[field.name] && errors[field.name] && <span className="text-danger">{errors[field.name]}</span>}
                </ReactPlaceholder>
            </div>
        </div>
    );

The form is initialized in another component (which acts as a page template for the website);

renderFormElements() {
        var formFields = this.props.detailsElements.map((item) => {
            switch (item.type) {
                case FormElementType.TextLine:
                    return <TextLine
                        name={item.name}
                        label={item.label}
                        disabled={!this.state.editMode}
                        loading={item.loading}
                        value={item.defaultValue}
                        key={'TextBox_' + item.name}
                    />
                case FormElementType.TextBox:
                    return <Field
                        type="text"
                        name={item.name}
                        label={item.label}
                        component={InputElements.TextBox}
                        disabled={!this.state.editMode}
                        loading={item.loading}
                        value={item.defaultValue}
                        key={'TextBox_' + item.name}
                    />
                case FormElementType.DropDown:
                    return <Field
                        name={item.name}
                        label={item.label}
                        component={InputElements.DropDown}
                        disabled={!this.state.editMode}
                        loading={item.loading}
                        value={item.defaultValue}
                        options={item.options}
                        key={'DropDown_' + item.name}
                    />
                case FormElementType.RadioGroup:
                    return <Field
                        type="radio"
                        name={item.name}
                        label={item.label}
                        component={InputElements.RadioGroup}
                        disabled={!this.state.editMode}
                        loading={item.loading}
                        value={item.defaultValue}
                        options={item.options}
                        key={'RadioGroup' + item.name}
                    />
                }
        });

        var initialValues:{ [k: string]: any } = {};
        this.props.detailsElements.map((item) => {
            initialValues[item.name] = item.defaultValue;
        })
        console.log(initialValues);

        var formSection =
            (<Formik initialValues={initialValues} onSubmit={(values, actions) => {
                setTimeout(() => {
                    alert(JSON.stringify(values, null, 2))
                    actions.setSubmitting(false)
                }, 1000)
            }}>
                <Form key="mainForm">
                    {formFields}
                </Form>
            </Formik>)

        return formSection;

I was assuming that the onChange event handler was taken care of by Formik, and that, if I didn't want to do special stuff, I did not need to provide anything to this. What am I missing here?

Thanks!

1

1 Answers

11
votes

your formFields function gets all of Formik props goodies. it contains handleChange - use this handler as your on change.

Also, make sure the field "id" is the same as the values key.

const {
  values,
  touched,
  errors,
  dirty,
  isSubmitting,
  handleChange,
  handleBlur,
  handleSubmit,
} = this.props;
<FormControl
      id="username"
      required
      placeholder="Enter Username"
      value={values.username}
      error={touched.username && errors.username}
      onChange={handleChange}
      onBlur={handleBlur}
    />