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.
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
There are few things which you need to change in your code.
when using Formik there is no need to maintain state explicitly to hold the form values . Formik will take care of it .
You are just changing the values but not notifying the formik to change its state.
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.
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 .