'Creating an array of objects from react events

I am trying to create a new object for ingredient quantity measure for each new ingredient the user creates. I can make the object for 1 of the ingredient-triad divs but I am stumped about how to create several objects with different ingredients added by user eg.

ingredientList = [
 {
   ingredient_name: flour,
   ingredient_quantity: 1,
   ingredient_measure: cup
 },
 {
   ingredient_name: water,
   ingredient_quantity: 1,
   ingredient_measure: tbsp
 }
]

etc. 


Here is where I have gotten to:

export default function Recipe() {
  const [name, setName] = useState('')
  const [method, setMethod] = useState('')
  const [ingredient, setIngredient] = useState('')
  const [ingredientyQty, setIngredientQty] = useState('')
  const [ingredientMeasure, setIngredientMeasure] = useState('')

  const ingredientList = []

  const recipeIngredient = {
    ingredient_name: ingredient,
    quantity: ingredientyQty,
    measure: ingredientMeasure,
  }

  ingredientList.push(recipeIngredient)

  const sendRecipeName = function (e) {
    e.preventDefault()

    fetch('http://localhost:3001/recipe', {
      method: 'POST',
      headers: { 'Content-type': 'application/json' },
      body: JSON.stringify({ name: name, method: method }),
    })
      .then((resp) => resp.json())
      .then((json) => console.log(json))
  }

  return (
    <div>
      [...]
          <div className="ingredient-triad">
            <input
              className="ingredient"
              type="text"
              onChange={(e) => setIngredient(e.target.value)}
            ></input>
            <input
              className="quantity"
              type="text"
              onChange={(e) => setIngredientQty(e.target.value)}
            ></input>
            <select
              className="dropdown"
              name="measure"
              id="measure"
              onChange={(e) => setIngredientMeasure(e.target.value)}
            >
              <option value="cup">cup</option>
              [...]
            </select>
          </div>
          <div className="ingredient-triad">
            <input
              className="ingredient"
              type="text"
              onChange={(e) => setIngredient(e.target.value)}
            ></input>
            <input
              className="quantity"
              type="text"
              onChange={(e) => setIngredientQty(e.target.value)}
            ></input>
            <select
              className="dropdown"
              name="measure"
              id="measure"
              onChange={(e) => setIngredientMeasure(e.target.value)}
            >
               <option value="cup">cup</option>
              [...]
            </select>
          </div>
          <div className="save-button-container">
            <button className="save-recipe" onClick={(e) => sendRecipeName(e)}>
              Submit Recipe
            </button>
          </div>
        </form>
      </div>
    </div>
  )
}


Solution 1:[1]


import React, { useState } from "react";

const init = {
  ingredient_name: "",
  quantity: "",
  measure: ""
};

export default function App() {
  const [ingredientList, setIngredientList] = useState([
    {
      ingredient_name: "",
      quantity: "",
      measure: ""
    }
  ]);

  const handleChange = (e, i) => {
    const { name, value } = e.target;
   
    setIngredientList((prevState) => {
      const newIngredientList = [...prevState];
      newIngredientList[i][name] = value;
      return [...newIngredientList];
    });
  };

  return (
    <>
      [...]
      {ingredientList.map((list, i) => (
        <div key={i} className="ingredient-triad">
          <input
            className="ingredient"
            name="ingredient_name"
            type="text"
            value={list.ingredient_name}
            onChange={(e) => handleChange(e, i)}
          ></input>
          <input
            className="quantity"
            name="quantity"
            type="text"
            value={list.quantity}
            onChange={(e) => handleChange(e, i)}
          ></input>
          <select
            className="dropdown"
            name="measure"
            id="measure"
            value={list.measure}
            onChange={(e) => handleChange(e, i)}
          >
            <option value="" disabled>
              --none--
            </option>
            <option value="cup">cup</option>
          </select>
          <button onClick={() => setIngredientList((prev) => [...prev, init])}>
            +
          </button>
        </div>
      ))}
      [...]
    </>
  );
}

I think this is what you are looking for :)

Solution 2:[2]

Try this below code:

export default function Recipe() {
    const [name, setName] = useState('')
    const [method, setMethod] = useState('')
    const [ingredientList, setIngredientList] = useState([])
    const [ingredient, setIngredient] = useState('')
    const [ingredientyQty, setIngredientQty] = useState('')
    const [ingredientMeasure, setIngredientMeasure] = useState('')
  
    console.log(ingredientList)
    const sendRecipeName = function (e) {
      e.preventDefault()

      const recipeIngredient = {
        ingredient_name: ingredient,
        quantity: ingredientyQty,
        measure: ingredientMeasure,
      }
      setIngredientList((prev) => [...prev, recipeIngredient])
  
      fetch('http://localhost:3001/recipe', {
        method: 'POST',
        headers: { 'Content-type': 'application/json' },
        body: JSON.stringify({ name: name, method: method }),
      })
        .then((resp) => resp.json())
        .then((json) => console.log(json))
    }
  
    return (
      <div>
        [...]
            <div className="ingredient-triad">
              <input
                className="ingredient"
                type="text"
                onChange={(e) => setIngredient(e.target.value)}
              ></input>
              <input
                className="quantity"
                type="text"
                onChange={(e) => setIngredientQty(e.target.value)}
              ></input>
              <select
                className="dropdown"
                name="measure"
                id="measure"
                onChange={(e) => setIngredientMeasure(e.target.value)}
              >
                <option value="cup">cup</option>
                [...]
              </select>
            </div>
            <div className="ingredient-triad">
              <input
                className="ingredient"
                type="text"
                onChange={(e) => setIngredient(e.target.value)}
              ></input>
              <input
                className="quantity"
                type="text"
                onChange={(e) => setIngredientQty(e.target.value)}
              ></input>
              <select
                className="dropdown"
                name="measure"
                id="measure"
                onChange={(e) => setIngredientMeasure(e.target.value)}
              >
                 <option value="cup">cup</option>
                [...]
              </select>
            </div>
            <div className="save-button-container">
              <button className="save-recipe" onClick={(e) => sendRecipeName(e)}>
                Submit Recipe
              </button>
            </div>
          </form>
        </div>
      </div>
    )
  }

Solution 3:[3]

First, I think you are missing the company field from your UpdateProductUserForm.

Add that in there:

class UpdateProductUserForm(AddUsersForm):
    first_nm = StringField('First Name*', validators=[DataRequired()])
    last_nm = StringField('Last Name*', validators=[DataRequired()])
    company = SelectField('Company*', validators=[DataRequired()], choices=[])
    disable = SubmitField('Deactivate')

Notice that we define it as an empty list. Then we update it however we want in the view:

@approvals.route('/productapproval/addproductUser/<int:prod_user_key>', methods=['GET', 'POST'])
def edit_product_users(prod_user_key):
    
    productUser = ProductUsers.query.get_or_404(prod_user_key)

    # get all the companies
    companies = [comp.prod_id for comp in Company.query.filter(Company.member_status!=500).all()]
 
    # move current company item to start of list
    current_company_index = companies.index(productUser.prod_id)
    companies.insert(0, companies.pop(current_company_index))

    form = UpdateProductUserForm()
    form.company.choices = companies
    form.first_nm.data = productUser.first_nm
    form.last_nm.data = productUser.last_nm

    if form.validate_on_submit():
        productUser.org_id = form.company.data
        productUser.first_nm = form.first_nm.data
        productUser.last_nm = form.last_nm.data

        db.session.add(productUser)
        db.session.commit()
        flash('User Account Updated', 'success')

        return redirect(url_for('approvals.users', prod_user_key=prod_user_key))

    return render_template('/productapproval/addusers.html', form=form)

I noticed you were fetching the user twice. You don't need to do that. Also you weren't properly adding the updated user to the database session. I've fixed those things in the above code.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 omnicron96
Solution 2 VMT
Solution 3