currently doing a recipe MERN project,
so far I have made a button to create an input of new ingredient for user,
however, I am stuck when I tried to add a button for removing current / extra ingredient input field
I tried the code from below https://codingstatus.com/add-remove-input-fields-dynamically-with-react-js/ using .map to embed the < input> and the < button>
but it doesn't work as expected the button does not response anything
I feel like it is supposed to work as well since all the logic makes sense to me however, not only does the remove button not work, but also the add button fail as well
can someone help me to take a quick look at the code
expected result is there is a remove button to the right of the input field, so user could manage how many ingredient to be put in the recipe
import React from "react";
import { useState } from "react";
import axios from "axios";
import { useGetUserID } from "../Hooks/useGetUserID";
import { useNavigate } from "react-router-dom";
const Create_recipe = () => {
const userId = useGetUserID(); // for below userOwner
const [recipe, setRecipe] = useState({
name: "",
ingredient: [],
instruction: "",
imageUrl: "",
cookingTime: 0,
userOwner: userId,
});
const navigate = useNavigate(); // for below push to another page
const handleChange = (event) => {
const { name, value } = event.target;
setRecipe({ ...recipe, [name]: value });
};
const handleAddIngredient = () => {
const newIngredient = [...recipe.ingredient, ""];
setRecipe({ ...recipe, newIngredient });
};
const handleRemoveIngredient = (index) => {
const updatedIngredient = [...recipe.ingredient];
updatedIngredient.splice(index, 1);
setRecipe({ ...recipe, updatedIngredient });
};
const handleIngredientChange = (event, index) => {
event.preventDefault();
const { value } = event.target;
const ingredient = [...recipe.ingredient];
ingredient[index] = value;
setRecipe({ ...recipe, ingredient }); //short handed notation
};
const handleSubmit = async (event) => {
event.preventDefault();
try {
const result = await axios({
method: "post",
url: "http://localhost:3001/recipe/create",
data: recipe,
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
},
});
alert("recipe created");
navigate("/");
} catch (err) {
if (err.response) alert(JSON.stringify(err.response.data));
}
};
return (
<div className="createRecipeSession">
<h2 className="createRecipeHeader">Create Recipe</h2>
<div className="createRecipeContainer">
<form onSubmit={handleSubmit} className="createFormDetail">
<div className="createRecipeSubtitle">
<label htmlFor="name">Name</label>
</div>
<input type="text" id="name" name="name" onChange={handleChange} />
<div className="createRecipeSubtitle">
<label htmlFor="ingredients">Ingredients</label>
</div>
<div>
{recipe.ingredient.map((ingredient, index) => (
<div className="ingredientOption" key={index}>
<div className="ingredientOption1">
<input
className="inputIngredient"
type="text"
name="ingredient"
value={ingredient}
onChange={(event) => handleIngredientChange(event, index)}
/>
</div>
<div className="ingredientOption2">
{recipe.ingredient.length !== 1 ? (
<button
className="removeIngredient"
type="button"
onClick={() => handleRemoveIngredient(index)}
> - </button>) : ""}
</div>
</div>
))}
<button
className="addIngredient"
type="button"
onClick={handleAddIngredient}>Add ingredient</button>
</div>
<div className="createRecipeSubtitle">
<label htmlFor="instruction">Instruction</label>
</div>
<textarea
id="instruction"
name="instruction"
onChange={handleChange}
/>
<div className="createRecipeSubtitle">
<label htmlFor="imageUrl">ImageUrl</label>
</div>
<input
type="text"
id="imageUrl"
name="imageUrl"
onChange={handleChange}
/>
<div className="createRecipeSubtitle">
<label htmlFor="cookingTime">CookingTime</label>
</div>
<input
type="number"
id="cookingTime"
name="cookingTime"
onChange={handleChange}
/>
<button className="createRecipeButton" type="submit">
Create recipe
</button>
</form>
</div>
</div>
);
};
export default Create_recipe;
In the function handleRemoveIngredient()
when setting the recipe state with setRecipe
you're adding everything you had before and a new property called updatedIngredient
, what you have to do is replace the ingredient
property.
const handleRemoveIngredient = (index) => {
const updatedIngredient = [...recipe.ingredient];
updatedIngredient.splice(index, 1);
setRecipe({ ...recipe, ingredient: updatedIngredient });
};
The same for the handleAddIngredient()
function, and ideally you would pass a value, which is going to be the new ingredient
const handleAddIngredient = (value) => {
const newIngredient = [...recipe.ingredient, value];
setRecipe({ ...recipe, ingredient: newIngredient });
};