React Formik Material-UI autocomplete: how to submit multiple selected values on submit

Viewed 668

I'm trying to figure out how to use Material-UI Autocomplete with Formik.

Here I've created a form which displays 3 question fields per page, which is working fine.

Since I'm very new to this and don't really understand Formik very well I'm having trouble with this type of input.

So what I'm doing here is that first there is a condition, you select (yes or no) depending on if you want to answer the question. After that there is the Autocomplete dropdown, from which you can select multiple options. The part where I'm having trouble is I don't know how to submit multiple selected options. The options you select from the autocomplete dropdown will go into the remedies array.

In the end it should return something like this:

question11: {
    agree: 'Yes',
    remedies: ['option you selected', 'another selected option']
}

So I want to be able to select multiple values from Autocomplete and populate them in the remedies: [] array.

The FormikControl is another thing I made which is just a bunch of switch statements which render a certain type of Input depending on the condition that is passed. In this case its returning the Input Component I posted below.

The form:

import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import { Formik, Form } from 'formik';
import * as yup from 'yup';
import FormikControl from './FormikControl';
import SurveyFormLayout from '../surveyForm/SurveyFormLayout';
import PrimaryBtn from '../../../components/buttons/PrimaryBtn';

const data = [
    {
        type: 'radioWithDropdown',
        question: 'Do you take any natural remedies? (Vitamins, minerals, amino acids, 
        herbs etc.)',
        name: 'question11',
        conditions: [ { key: 'yes', value: 'Yes' }, { key: 'no', value: 'No' } ],
        options: [
            { key: 'Option 11', value: 'word' },
            { key: 'Option 12', value: 'another word' },
            { key: 'Option 13', value: 'some other' },
            { key: 'Option 14', value: 'random' }
        ]
    }
]

const InputAssesment = () => {

    const initialValues = {
        question11: {
            agree: '',
            remedies: []
        }
    };

    const validationSchema = yup.object({
        question11: yup.object().shape({
            agree: yup.string(),
            remedies: yup.array()
        })
    });

    return (
        <SurveyFormLayout>
            
            <div className="survey-form__container">
                <FormikStepper 
                    initialValues={initialValues} 
                    validationSchema={validationSchema} 
                    onSubmit={() => {}}
                >
                    <FormikStep>
                        <FormikControl
                            control="conditionWithSelectMultiple"
                            label={data[9].question}
                            name="question11.remedies"
                            options={data[9].options}
                            conditionName="question11.agree"
                            conditionOptions={data[9].conditions}
                        />
                    </FormikStep>
                </FormikStepper>
            </div>

        </SurveyFormLayout>
    )
}

export function FormikStep({ children }) {
    return <div className="formik-step">{children}</div>;
}

export function FormikStepper({ children, ...props }) {
    const childrenArray = React.Children.toArray(children);
    const [ step, setStep ] = useState(0);
    const currentChild = childrenArray[step];

    function isLastStep() {
        return step === childrenArray.length - 1;
    }

    return (
        <Formik
            {...props}
            onSubmit={async (values, helpers) => {
                if (isLastStep()) {
                    await props.onSubmit(values, helpers);
                } else {
                    setStep((s) => s + 1);
                }
                console.log(values);
            }}
        >
            <Form autoComplete="off" className="formik-form">
                {currentChild}
                <div className="survey-btns-container">
                    {step > 0 ? (
                        <button
                            className="btn-secondary survey-back-btn"
                            type="button"
                            onClick={() => setStep((s) => s - 1)}
                        >
                            Back
                        </button>
                    ) : null}
                    <PrimaryBtn text={isLastStep() ? 'Submit' : 'Next'} type="submit" />
                </div>
            </Form>
        </Formik>
    );
}

The input component:

import React from 'react';
import { Field } from 'formik';

import Checkbox from '@material-ui/core/Checkbox';
import TextField from '@material-ui/core/TextField';

import { Autocomplete } from 'formik-material-ui-lab';
import CheckBoxOutlineBlankIcon from '@material-ui/icons/CheckBoxOutlineBlank';
import CheckBoxIcon from '@material-ui/icons/CheckBox';

const icon = <CheckBoxOutlineBlankIcon fontSize="small" />;
const checkedIcon = <CheckBoxIcon fontSize="small" />;

const ConditionWithSelectMultiple = (props) => {
    const { label, name, options, conditionName, conditionOptions, ...rest } = props;

    return (
        <div className="question-field">
            <label className="survey-question-h">{label}</label>

            <div className="radio-options-container">
                <Field name={conditionName} {...rest}>
                    {({ field }) => {
                        return conditionOptions.map((option) => {
                            return (
                                <div key={option.key} className="radio-button-option">
                                    <input
                                        className="radio-button"
                                        type="radio"
                                        id={option.value}
                                        {...field}
                                        value={option.value}
                                        checked={field.value === option.value}
                                    />
                                    <div className="radio-button-gap" />
                                    <label htmlFor={option.value} className="radio-button-option-label">
                                        {option.value}
                                    </label>
                                </div>
                            );
                        });
                    }}
                </Field>
            </div>

            <Field
                name="name"
                component={Autocomplete}
                multiple
                options={options}
                disableCloseOnSelect
                getOptionLabel={(option) => option.key}
                renderOption={(option, { selected }) => (
                    <React.Fragment>
                        <Checkbox icon={icon} checkedIcon={checkedIcon} style={{ marginRight: 8 }} checked={selected} />
                        {option.key}
                    </React.Fragment>
                )}
                style={{ width: 500 }}
                renderInput={(params) => <TextField {...params} variant="outlined" placeholder="Select" />}
            />
        </div>
    );
};

export default ConditionWithSelectMultiple;

Any help is more than welcome

0 Answers
Related