i have a website where i have a form, the form has 3 fields which can be addedd multiple times on click, my code is like below:
$(document).ready(function() {
var max_fields = 10;
var wrapper = $(".container1");
var add_button = $("#niy");
var x = 1;
$(add_button).click(function(e) {
e.preventDefault();
if (x < max_fields) {
x ;
$(wrapper).append('<div ><div ><label for="client_type">Service Type</label><input type="text" id="client_type" required name="service[]"></div></div><div ><div ><label for="client_type">Price</label><input type="text" id="client_type" required name="price[]"></div></div><div ><div ><label for="client_type">Total</label><input type="text" id="total" required name="total[]"></div></div>'); //add input box
} else {
alert('You Reached the limits')
}
});
$(wrapper).on("click", ".delete", function(e) {
e.preventDefault();
$(this).parent('div').remove();
x--;
})
});
$('input[name="price[]"]').change(function() {
$('input[name="total[]"]').val($(this).val());
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div >
<div >
<!-- Form -->
<div >
<label for="client_type">Service Type</label>
<input type="text" id="client_type" required name="service[]">
</div>
</div>
<div >
<!-- Form -->
<div >
<label for="client_type">Price</label>
<input type="text" id="client_type" required name="price[]">
</div>
</div>
<div >
<!-- Form -->
<div >
<label for="client_type">Total</label>
<input type="text" id="client_type" required name="total[]">
</div>
</div>
</div>
<a id="niy" style="color:white">Add New Service Field
<span style="font-size:16px; font-weight:bold;"> </span>
</a>
i want the total field to show the value from its respective price field, however here only first row does that, can anyone please tell me how to fix this, thanks in advance
CodePudding user response:
The main issue in your code is because you only bind the change
event which updates the value of the fields when the page first loads. This ignores all the fields which are added dynamically. To fix this use delegated event handlers - exactly as you are for the .delete
button.
That being said, it's worth noting that there's several other issues which need to be addressed:
- Don't repeat the same
id
attribute value in the DOM. They need to be unique. Also, don't useid
at all in content which can be repeated dynamically. Useclass
attributes instead. - Don't use inline styling with the
style
attribute. It's bad practice to put one type of code in another, eg. CSS in your HTML, or HTML in your JS. In this case use an external stylesheet. - Similarly, don't put HTML in your JS. Clone existing content instead of dumping a lot of HTML in the JS. In your original, if you changed the HTML template, then you'd need to also remember to update the JS file too. Using cloning avoids this problem.
- Don't double-wrap your jQuery objects. Eg.
add_button
is already a jQuery object, you don't need to use$(add_button)
. It's worth prefixing variable names that hold jQuery objects with$
for this reason. - Don't use global variables where possible. They're bad practice for a variety of reasons, not least of which is that they lead to more length and harder to maintain code. A better approach in this case is to retrieve the number of elements already existing in the DOM and compare that to the known limit.
With all that said, here's a working demo:
jQuery($ => {
var max_fields = 10;
var $container = $(".container");
var $add_button = $("#niy");
$add_button.on('click', e => {
e.preventDefault();
if ($('.row').length >= max_fields) {
alert('You Reached the limits');
return;
}
let $newContent = $('.row:first').clone().appendTo($container);
$newContent.find(':input').val('');
});
$container.on("click", ".delete", e => {
e.preventDefault();
$(e.target).closest('.row').remove();
})
$container.on('change', '.price', e => {
$(e.target).closest('.row').find('.total').val(e.target.value);
});
});
body {
background-color: #CCC;
}
#niy {
color: white;
}
#niy span {
font-size: 16px;
font-weight: bold;
}
label {
width: 100px;
display: inline-block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div >
<div >
<div >
<div >
<label for="client_type">Service Type</label>
<input type="text" required name="service[]">
</div>
</div>
<div >
<div >
<label for="client_type">Price</label>
<input type="text" required name="price[]">
</div>
</div>
<div >
<div >
<label for="client_type">Total</label>
<input type="text" required name="total[]">
</div>
</div>
</div>
</div>
<a id="niy" >
Add New Service Field
<span> </span>
</a>
CodePudding user response:
try below snippet once, you will find runtime oninput updating totals. That imrpoves user experience.
$(document).ready(function() {
var max_fields = 10;
var wrapper = $(".container1");
var add_button = $("#niy");
var x = 1;
$(add_button).click(function(e) {
e.preventDefault();
if (x < max_fields)
{
x ;
$(wrapper).append('<div ><div ><label for="service_type' x '">Service Type</label><input type="text" data-id="' x '" id="service_type' x '" required name="service[]"></div></div><div ><div ><label for="price_type' x '">Price</label><input type="text" data-id="' x '" id="price_type' x '" required name="price[]"></div></div><div ><div ><label for="total_type' x '">Total</label><input type="text" data-id="' x '" id="total_type' x '" readonly name="total[]"></div></div>');
}
else
{
alert('You Reached the limits')
}
});
$(wrapper).on("click", ".delete", function(e) {
e.preventDefault();
$(this).parent('div').remove();
})
});
$(document).on('input', '.service_type, .price_type', function(){
var id = $(this).attr('data-id');
if(id > 0)
{
var service_type = parseFloat($('#service_type' id).val()) || 0;
var price_type = parseFloat($('#price_type' id).val()) || 0;
var total_type = service_type price_type;
$('#total_type' id).val(total_type.toFixed(2));
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div >
<div >
<!-- Form -->
<div >
<label for="service_type1">Service Type</label>
<input type="text" id="service_type1" data-id="1" required name="service[]">
</div>
</div>
<div >
<!-- Form -->
<div >
<label for="price_type1">Price</label>
<input type="text" id="price_type1" data-id="1" required name="price[]">
</div>
</div>
<div >
<!-- Form -->
<div >
<label for="total_type1">Total</label>
<input type="text" id="total_type1" data-id="1" readonly name="total[]">
</div>
</div>
</div>
<a id="niy" >Add New Service Field
<span style="font-size:16px; font-weight:bold;"> </span>
</a>