简体   繁体   中英

Deleting dynamically created form elements

I've been trying to make a dynamic form so users can add an array of ingredients with the form they are submitting. I was able to add input elements dynamically but would also like to remove them dynamically. I'm trying to do all this with basic javascript and no jquery. The problem I'm running to is that if I put my delete button snippet inside the addBtn click event I'm only able to delete one item of my choosing. If I try to put the snippet outside the click event I can't grab the array of elements I want through querySelectorAll, because the query is made before the addBtn event listener goes off and before the elements are created. Thanks in advance!

 const ingredients = () => { const container = document.querySelector(".show-ingredients"); const addBtn = document.querySelector(".add-ingredient"); const newIngredient = document.querySelector("#input-ingredients"); let ingredients = []; newIngredient.required = true; addBtn.addEventListener("click", async() => { newIngredient.required = false; ingredients.push(` <div class="ingredient-container"> <input class='ingredient' type="text" value='${newIngredient.value}' required > <div class="controls delete"> <a class="delete-ingredient"> <span class="ingredient-bar"></span> </a> </div> </div>`); container.innerHTML = ingredients.join(""); newIngredient.value = ""; }); var deleteBtn = document.querySelectorAll(".delete-ingredient"); console.log(deleteBtn); for (let i = 0; i < deleteBtn.length; i++) { deleteBtn[i].addEventListener("click", async() => { console.log(i); // ingredients.splice(i, 1); // container.innerHTML = ingredients.join(''); }); } if (ingredients.length == 0) { newIngredient.required = true; } }; ingredients();
 .form-container { display: flex; text-align: center; flex-direction: column; text-align: center; justify-content: center; align-items: center; transition: all 0.5s ease-in-out; } .form-container input { width: 400px; max-width: 100%; height: 40px; padding-left: 10px; margin-bottom: 5px; } /* Add/delete ingredient */ .ingredient-wrapper { width: 400px; max-width: 100%; display: flex; flex-direction: column; } .ingredient-container { display: flex; align-items: center; justify-content: space-between; height: 40px; width: 400px; max-width: 100%; border: 1px solid grey; margin-bottom: 5px; } .controls, .controls.delete { background-color: green; height: 100%; width: 28px; padding-left: 1px; } .controls.delete { background-color: red; } .ingredient { margin-bottom: 0px; width: 100%; height: 100%; background: none; } .add-ingredient, .delete-ingredient { width: 28px; width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; transition: 0.5s ease-in-out; cursor: pointer; } .ingredient-bar::before { content: ""; background-color: white; display: block; height: 2px; width: 13px; transform: rotate(90deg); } .ingredient-bar { background-color: white; height: 2px; width: 13px; } .delete-ingredient { background-color: red; } .delete-ingredient .ingredient-bar::before { display: none; }
 <form action="" class="form-container" id="wrapper"> <input type="text" placeholder="What's cookin?" id="input-title" style="margin-top: 20px;" required> <div class="ingredient-wrapper"> <div class="ingredient-container"> <input type="text" placeholder="Ingredients" id="input-ingredients" style="border: none; margin-bottom: 0px; width: 400px;max-width:100%; height: 100%;"> <div class="controls"> <a class="add-ingredient"> <span class="ingredient-bar"></span> </a> </div> </div> <div class="show-ingredients"></div> </div> <input type="text" placeholder="Description/Instructions" id="input-description" required> <button type="submit" class="add-btn">Add post</button> </form>

An example codepen: https://codepen.io/benleem/pen/gOxgXWL (the css is messed up but it functions the same)

You should be able to get the desired result by moving both the .delete-ingredient selector and the addEventListener into a separate function.

Here's a snippet where it logs the position in the deletBtn array. I didn't change the HTML or CSS. Another small note I should add is that the ingredients array is not correctly connected with the delete buttons since you re-declare that array each time (global versus local arrays). Howver, you don't really need that array since you can select the specific element with deleteBtn[i] , which can then be deleted with the JavaScript .removeChild functionality.

 const ingredients = () => { const container = document.querySelector(".show-ingredients"); const addBtn = document.querySelector(".add-ingredient"); const newIngredient = document.querySelector("#input-ingredients"); let ingredients = []; newIngredient.required = true; addBtn.addEventListener("click", async () => { newIngredient.required = false; ingredients.push(` <div class="ingredient-container"> <input class='ingredient' type="text" value='${newIngredient.value}' required > <div class="controls delete"> <a class="delete-ingredient"> <span class="ingredient-bar"></span> </a> </div> </div>`); container.innerHTML = ingredients.join(""); newIngredient.value = ""; deleteIngredient(ingredients, container); }); if (ingredients.length == 0) { newIngredient.required = true; } }; const deleteIngredient = (list, wrapper) =>{ let ingredients = list; let container = wrapper; var deleteBtn = document.querySelectorAll('.delete-ingredient'); for (let i = 0; i < ingredients.length; i++) { deleteBtn[i].addEventListener('click', async () =>{ console.log(i); ingredients.splice(i, 1); container.innerHTML = ingredients.join(''); deleteIngredient(ingredients, container); }); } } ingredients();
 .form-container { display: flex; text-align: center; flex-direction: column; text-align: center; justify-content: center; align-items: center; transition: all 0.5s ease-in-out; } .form-container input { width: 400px; max-width: 100%; height: 40px; padding-left: 10px; margin-bottom: 5px; } /* Add/delete ingredient */ .ingredient-wrapper { width: 400px; max-width: 100%; display: flex; flex-direction: column; } .ingredient-container { display: flex; align-items: center; justify-content: space-between; height: 40px; width: 400px; max-width: 100%; border: 1px solid grey; margin-bottom: 5px; } .controls, .controls.delete { background-color: green; height: 100%; width: 28px; padding-left: 1px; } .controls.delete { background-color: red; } .ingredient { margin-bottom: 0px; width: 100%; height: 100%; background: none; } .add-ingredient, .delete-ingredient { width: 28px; width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; transition: 0.5s ease-in-out; cursor: pointer; } .ingredient-bar::before { content: ""; background-color: white; display: block; height: 2px; width: 13px; transform: rotate(90deg); } .ingredient-bar { background-color: white; height: 2px; width: 13px; } .delete-ingredient { background-color: red; } .delete-ingredient .ingredient-bar::before { display: none; }
 <form action="" class="form-container" id="wrapper"> <input type="text" placeholder="What's cookin?" id="input-title" style="margin-top: 20px;" required> <div class="ingredient-wrapper"> <div class="ingredient-container"> <input type="text" placeholder="Ingredients" id="input-ingredients" style="border: none; margin-bottom: 0px; width: 400px;max-width:100%; height: 100%;"> <div class="controls"> <a class="add-ingredient"> <span class="ingredient-bar"></span> </a> </div> </div> <div class="show-ingredients"></div> </div> <input type="text" placeholder="Description/Instructions" id="input-description" required> <button type="submit" class="add-btn">Add post</button> </form>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM