0

I have a dilemma that I can't find a solution to. I want to import many products while they may have the same category so when I click "+", the display will add a similar row like a picture enter image description here I have seen many tutorials on the internet and followed them but they all failed. I don't know how to do this. Please help me! Thank you very much

state = {
  listItems: [],
  userInput: this.need,
}

need = {
  category: "",
  name: "",
  quantity: ""
}
    handleChange = (event) => {
        const target = event.target;
        const value = target.value;
        const name = target.name;
        let userInput = { ...this.state.userInput };
        userInput[name] = value;
        this.setState({ userInput });
    }
    submitHandler = e => {
        e.preventDefault()
        this.setState({
            listItems: [...this.state.listItems, this.state.userInput],
        })
    }
<Form>
<Form.Group id="need">
    <Row>
     <Col md="3">
       <label>Category</label>
       <select name="category" className="form-control" onChange={this.handleChange}>
         <option value="1">Water</option>
         <option value="2">Food</option>
       </select>
    </Col>
    <Col md="4">
      <label>Name</label>
        <Input
           name="name"
           className="form-control-alternative"
           onChange={this.handleChange}
           type="text"
         />
    </Col>
    <Col md="4">
      <label>Quantity</label>
      <Input
        name="quantity"
        className="form-control-alternative"
        type="text"
        onChange={this.handleChange}
      />
   </Col>
   <Col>
<i style={{ marginTop: 45 }} onClick={submitHandler} >Add more</i>
   </Col>
</Row>
</Form.Group>
</Form>

CodeSandbox!

2
  • I didn't get it. I check your sandbox. And, I filled the fields and clicked Add More, nothing happened. What is the desired behavior? Commented Apr 1, 2021 at 16:50
  • 1
    In the display, I have a form with 3 tags: option, 2 input (I call it is a form1). When I click Add more, I want to display one more form1 on the below. In the picture I upload, when load page, only have a row but when I click +/Add more it will display a similar row so I have 2 rows. I want to ask everyone how can I do that Commented Apr 1, 2021 at 17:09

1 Answer 1

2

For this kind of form, I prefer using formik to this.setState.

Solution 1. this.setState

I would design the state as follow

this.state = {
  form: [
    {
      category: "",
      name: "",
      quantity: 0,
    },
  ],
};

and methods for adding more items, edit their content

handleAdd = () => {
  this.setState({
    form: [
      ...this.state.form,
      {
        category: "",
        name: "",
        quantity: 0,
      },
    ]
  });
};

handleEditFieldOfItem = (event, itemIndex, fieldName) => {
  const value = event.target.value;
  this.setState({
    form: this.state.form.map((item, index) => {
      if (index === itemIndex) {
        return { ...item, [fieldName]: value };
      }
      return item;
    })
  });
};

and I would render those items as follow:

render() {
  return (
    <div>
      {this.state.form.map((item, index) => {
        return (
          <div key={index}>
            <div>
              <select value={item.category} onChange={(event) => { this.handleEditFieldOfItem(event, index, 'category'); }}>
                <option value="water">Water</option>
                <option value="food">Food</option>
              </select>
            </div>
            <div>
              <input type="text" value={item.name} onChange={(event) => { this.handleEditFieldOfItem(event, index, 'name'); }} />
            </div>
            <div>
              <input type="text" value={item.quantity} onChange={(event) => { this.handleEditFieldOfItem(event, index, 'quantity'); }} />
            </div>
          </div>
        );
      })}
      <button onClick={this.handleAdd}>Add</button>
    </div>
  );
}

Solution 2. Using Formik (with FieldArray component)

Formik comes with the abilities to validate, handle nested values, ...

You should check out Formik documentation first.

import { Formik, Field, FieldArray } from "formik";

// ...

<Formik
  initialValues={{
    form: [
      {
        category: "",
        name: "",
        quantity: 0
      }
    ]
  }}
  onSubmit={(values, helpers) => {
    // 
  }}
>
  {(formikProps) => {
    const { values, handleSubmit } = formikProps;
    return (
      <>
        <FieldArray name="form">
          {(arrayHelpers) => {
            return (
              <div>
                {values.form.map((item, index) => {
                  return (
                    <div key={index}>
                      <Field as="select" name={`form.${index}.category`}>
                        <option value="water">Water</option>
                        <option value="food">Food</option>
                      </Field>
                      <Field name={`form.${index}.name`} />
                      <Field name={`form.${index}.quantity`} />
                    </div>
                  );
                })}
                <div>
                  <button onClick={() => arrayHelpers.push({ category: '', name: '', quantity: 0 })}>Add</button>
                </div>
              </div>
            )}}
        </FieldArray>
        <button type="submit">Submit</button>
      </>
    );
  }}
</Formik>
Sign up to request clarification or add additional context in comments.

1 Comment

Cảm ơn bạn nhiều. Mình cũng biết Formik nhưng chỉ sử dụng ở mức cơ bản nhờ bạn mà mình biết thêm cách dùng Formik

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.