Venkat
Venkat

Reputation: 19

Need help to remove items dynamically using pure javascript

Requirements:

  1. A new text box should appear with a delete button at closing after clicking '+Add Stop'.

  2. If a delete(x) button is clicked, the respective text box should be removed and Stop #(sequence numbering) should be changed as well.

Need help on:

I have tried to achieve the both above requirements. I get results for #1. But for #2, After adding more items, the delete button works/removes only the last added item only but it should work the same for all items.

Stop # sequence number should be maintained after the removal of an item(s). I need help with this logic also.

HTML:

    <form action="https://www.example.com" method="POST">
        <label for="stype">Service Type:</label>
        <select id="stype" name="service-type">
            <option disabled="disabled" selected="selected">Choose Service</option>
            <option value="From Airport">From Airport</option>
            <option value="To Airport">To Airport</option>
        </select><br/><br/>

        <label for="fullname">Name: </label><input id="fullname" name="name" size="20" type="text" maxlength="20" placeholder="John Doe" required /><br/><br/>
        <label for="phone">Phone: </label><input id="phone" name="phone" maxlength="12" type="tel" placeholder="012-345-6789" required /><br/><br/>
        <label for="email">Email: </label><input id="email" name="email" size="30" type="email" maxlength="30" placeholder="[email protected]" required /><br/><br/>

        <label for="ptime">Pickup time </label><input id="ptime" name="pickup-time" type="time" required /><br/><br/>
        <label for="pdate">Pickup Date </label><input id="pdate" name="pickup-date" type="date" required /><br/><br/>
        <div id="add_stop_here">
            
        </div>
        <input type="button" id="add" value="+Add Stop" onclick="test();" />
    </form>

JavaScript:

var counter = 0;
function test () {
    counter += 1;
    var addHtml = '\
    <div class="input-box">\
        <label for="stop'+counter+'">Stop '+counter+':</label>\
        <input type="text" id="stop'+counter+'" name="stop"/ >&nbsp;&nbsp;<a id="rmv'+counter+'" class="remove_stop" href="#">x</a>\
    </div>';

    var add_hre = document.getElementById("add_stop_here");
    add_hre.innerHTML += addHtml;

document.querySelector("#rmv"+counter)
.addEventListener('click', function(){
  var removeEl = this.parentNode;
  add_hre.removeChild(removeEl);
});
}

Upvotes: 0

Views: 146

Answers (2)

trincot
trincot

Reputation: 350272

Some issues to take care of:

  • To make this work, I would refrain from using id attributes that have a sequential number. It is not best practice.

    Instead, in order to link a label element with its input element, make the input element a child of the corresponding label element. Now the id and for attributes are no longer needed.

  • Don't use innerHTML += as that will reset the values of the inputs that are already in the document, and will remove the event listeners. Instead use insertAdjacentHTML.

  • To keep the numbering in pace, use a span element that only has that number, and renumber all those span elements after every change. You can also use it after an insert, just to keep the code clean, and avoid that you need to maintain a counter.

  • To avoid that you need to attach a new event handler for every new element, listen to click events on the container element, and then check in that single handler which element was clicked. This is called event delegation.

  • Don't name your function test. Give it a useful name, like insertBusStop.

  • Instead of binding that handler via HTML attribute, bind it via code.

  • For multi-line strings you can use back tick delimiters (template literals)

  • I'd suggest that after clicking the Add button, the focus is put on the newly created input element. This facilitates the input procedure for the user.

Here is how that would work:

var add_hre = document.getElementById("add_stop_here");
document.getElementById("add").addEventListener("click", addBusStop);

function addBusStop() {
    var addHtml = `
    <div class="input-box">
        <label>
        Stop <span class="stop_number"></span>
        <input type="text" name="stop"/>&nbsp;&nbsp;<a class="remove_stop" href="#">x</a>
        </label>
    </div>`;
    add_hre.insertAdjacentHTML("beforeend", addHtml);
    renumber();
    add_hre.querySelector(".input-box:last-child input").focus();
}

function renumber() {
    let i = 1;
    for (let labelSpan of add_hre.querySelectorAll(".stop_number")) {
        labelSpan.textContent = i++;
    }
}

// Use event delegation
add_hre.addEventListener('click', function(e) {
    if (!e.target.classList.contains("remove_stop")) return;
    var removeEl = e.target.parentNode.parentNode;  // need one more level now
    add_hre.removeChild(removeEl);
    renumber();
});
<div id="add_stop_here"></div>
<input type="button" id="add" value="+Add Stop"/>

Upvotes: 3

Sumit Sharma
Sumit Sharma

Reputation: 1237

You can do this with each() and find() function easily.

var counter = 0;

$("#add").click(function () {
  counter++;
  $("#add_stop_here").append(
    '<div class="input-box"><label for="stop' +
      counter +
      '">Stop' +
      counter +
      ': <input type="text" id="stop' +
      counter +
      '" name="stop"/ ></label>&nbsp;&nbsp;<a id="rmv' +
      counter +
      '" class="remove_stop" href="#">X</a></div>'
  );
});

$(document).on("click", ".remove_stop", function () {
  $(this).closest("div").remove(); //use closest here
  $("#add_stop_here .input-box").each(function (index) {
    $(this)
      .find("label:eq(0)")
      .attr("id", "stop" + (index + 1));

    $(this)
      .find("label:eq(0)")
      .html("Stop" + (index + 1) + '<input type="text" name="stop" />');
  });
  counter--;
});
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

<form action="https://www.example.com" method="POST">
  <label for="stype">Service Type:</label>
  <select id="stype" name="service-type">
    <option disabled="disabled" selected="selected">Choose Service</option>
    <option value="From Airport">From Airport</option>
    <option value="To Airport">To Airport</option></select
  ><br /><br />

  <label for="fullname">Name: </label
  ><input
    id="fullname"
    name="name"
    size="20"
    type="text"
    maxlength="20"
    placeholder="John Doe"
    required
  /><br /><br />
  <label for="phone">Phone: </label
  ><input
    id="phone"
    name="phone"
    maxlength="12"
    type="tel"
    placeholder="012-345-6789"
    required
  /><br /><br />
  <label for="email">Email: </label
  ><input
    id="email"
    name="email"
    size="30"
    type="email"
    maxlength="30"
    placeholder="[email protected]"
    required
  /><br /><br />

  <label for="ptime">Pickup time </label
  ><input id="ptime" name="pickup-time" type="time" required /><br /><br />
  <label for="pdate">Pickup Date </label
  ><input id="pdate" name="pickup-date" type="date" required /><br /><br />
  <div id="add_stop_here"></div>
  <input type="button" id="add" value="+Add Stop" />
</form>

Upvotes: 0

Related Questions