Search code examples
reactjstypescriptreact-hookssemantic-uiformik

How to get value of dropdown using Semantic UI React, with hooks


I am developing an form where in, there are 3 drop downs in a row, and the last drop down can take multiple values. Also, there is an option to add or delete a row. When user adds a row, a new row with the three drop down appears.

I have used React, React Semantic UI, Hooks, Typescript to implement this.

Now, I am trying to get the value of the selected items from the dropdown when the form is submitted. But, not sure what i'm missing to achieve this. When I add a row, the new row is taking the selected items of the top row.

Image of my UI

My code is like this:

import { Formik } from "formik";
import React, { Fragment } from "react";
import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { setModalStates } from "redux/actions/appActions";
import { IStore } from "redux/interfaces/types";
import { Button, Dropdown, Form, Grid, Icon } from "semantic-ui-react";

const QueryBuilder = () => {

    const [rulesetList, setrulesetList] = useState([{ entity: "", condition: "", val: "" }]);
    const mainField = [
        {
            key: "fruit",
            text: "fruit",
            value: "fruit"
        },
        {
            key: "color",
            text: "color",
            value: "color"
        },
        {
            key: "taste",
            text: "taste",
            value: "taste"
        }
    ]

    const operation = [
        {
            key: "is ",
            text: "is ",
            value: "is "
        },
        {
            key: "is not ",
            text: "is not ",
            value: "is not "
        }
    ]
    const options = [
        {
            key: "apple",
            text: "apple",
            value: "apple"
        },
        {
            key: "yellow",
            text: "yellow",
            value: "yellow"
        },
        {
            key: "sweet",
            text: "sweet",
            value: "sweet"
        },
    ]

    const [dropDownOptions, setDropDownOptions] = useState(options);
    const [currentValue, setCurrentValue] = useState("");
    const handleAddition = (e: any, { value }: any) => {
        setDropDownOptions((prevOptions) => [
            ...prevOptions,
            { key: value, text: value, value },
        ]);
    };

    const handleChange = (e: any, { value }: any) => {
        setCurrentValue(value);
    }

    const handleRemoveClick = (index: number) => {
        const list = [...rulesetList];
        list.splice(index, 1);
        setrulesetList(list);

    };

    const handleAddClick = () => {
        setrulesetList([...rulesetList, { entity: "", condition: "", val: "" }]);
        setDropDownOptions(options)
    };

    const initialValues = {
        mainField : "",
        operation: "",
        resultant_value: ""
    }

    return (
        <Fragment>
            {rulesetList.map((x, i) => {
                return (
                    <Grid >
                        <Grid.Row className={"rulesetGrid fluid"} >
                            <Formik
                                initialValues={initialValues}
                                onSubmit={values => {
                                    console.log("here",values)
                                }}

                            >
                                {
                                    ({ handleSubmit, values, setValues }) => (
                                        <Form onSubmit={handleSubmit} className={"rulesetForm"}>
                                            {i == 0 ? <p className="condition"> If</p> : <p className="condition"> And</p>}

                                            <Dropdown
                                                name="mainField"
                                                className={"dropdown fieldDropdown"}
                                                widths={2}
                                                placeholder='Fruit'
                                                fluid
                                                selection
                                                options={mainField}
                                            />

                                            <Dropdown
                                                name="operation"
                                                className={"dropdown operationDropdown"}
                                                widths={2}
                                                placeholder='Operation'
                                                fluid
                                                selection
                                                options={operation}
                                            />
                                            <Dropdown
                                                name="resultant_value"
                                                className={"dropdown valueDropdown"}
                                                widths={1}
                                                placeholder='Value'
                                                fluid
                                                search
                                                allowAdditions
                                                selection
                                                multiple
                                                options={dropDownOptions}
                                                value={currentValue }
                                                onAddItem={handleAddition}
                                                onChange={handleChange}
                                            />

                                            {rulesetList.length - 1 === i && <Icon className={"Plus plusIcon"} onClick={handleAddClick} />}
                                            {rulesetList.length !== 1 && <Icon className={"LineThicknessMedium signal-danger crossIcon"} onClick={() => handleRemoveClick(i)} />}
                                        </Form>
                                    )
                                }
                            </Formik>
                        </Grid.Row>

                    </Grid>
                );
            }
            )}
            <div>
                <div style={{ marginTop: "1rem" }}>
                    <Button
                        floated="right"
                        type="submit"
                        variant="contained"
                        primary={true}
                    >
                        Submit
                    </Button>
                </div>
            </div>
        </Fragment>
    );

}
export default QueryBuilder

Solution

  • There are few things which you need to change in your code.

    1. when using Formik there is no need to maintain state explicitly to hold the form values . Formik will take care of it .

    2. You are just changing the values but not notifying the formik to change its state.

    3. Since you are rendering the array of Fields , you can make use of the Formik FieldArray component which comes with the bunch of helpers like pushing a new row, removing the row and updating the value of a field within each row.

    4. Your submit was not working because you have the submit button outside the <Formik /> component . So clicking on submit button will not call the onSubmit of Formik .

    Have refactored your code to make use of the FieldArray .

    Working codesandbox