Home > Software engineering >  Deleting dynamically created form elements
Deleting dynamically created form elements

Time:10-26

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 >
            <input class='ingredient' type="text" value='${newIngredient.value}' required >
            <div >
                <a >
                    <span ></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>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

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

CodePudding user response:

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 >
            <input class='ingredient' type="text" value='${newIngredient.value}' required >
            <div >
                <a >
                    <span ></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>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related