Reputation: 19
Requirements:
A new text box should appear with a delete button at closing after clicking '+Add Stop'.
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"/ > <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
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"/> <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
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> <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