Here is the code I want to use to allow user control the product quantity in a shopping cart. The problem is, if there are 2 product or more in the same cart, if I try to increase one product quantity, it will increase all products quantity. I would like to use the foreach function in the jQuery code , I tried to insert PHP $i , but it didn't work. can someone help please ? I just want separate product quantity increase/decrease for each product (form)
<?php
if (isset($_POST['submit'])) {
$product_quantity= $_POST['quantity'];
} else {$product_quantity= "1";}
?>
<form method='POST' action=''>
<input type = "submit" value="-" name = "submit" value = "Submit" field="quantity" >
<input type='text' name='quantity' value='<?php echo $product_quantity; ?>' class='qty form-control' />
<input type = "submit" value=' ' name = "submit" value = "Submit" class='qtyplus btn btn-success btn-sm' field='quantity' >
</form>
<form method='POST' action=''>
<input type = "submit" value="-" name = "submit" value = "Submit" field="quantity" >
<input type='text' name='quantity' value='<?php echo $product_quantity; ?>' class='qty form-control' />
<input type = "submit" value=' ' name = "submit" value = "Submit" class='qtyplus btn btn-success btn-sm' field='quantity' >
</form>
<script src="jquery/jquery.min.js"></script>
<script>
jQuery(document).ready(function() {
$('.qtyplus').click(function(e) {
fieldName = $(this).attr('field');
var currentVal = parseInt($('input[name=' fieldName ']').val());
if (!isNaN(currentVal)) {
$('input[name=' fieldName ']').val(currentVal 1);
} else {
$('input[name=' fieldName ']').val(1);
}
});
$(".qtyminus").click(function(e) {
fieldName = $(this).attr('field');
var currentVal = parseInt($('input[name=' fieldName ']').val());
if (!isNaN(currentVal) && currentVal > 1) {
$('input[name=' fieldName ']').val(currentVal - 1);
} else {
$('input[name=' fieldName ']').val(1);
}
});
});
</script>
CodePudding user response:
In your click event handler you were fetching the input element using a selector in the whole document that was going to return multiple elements.
Instead you should rely on the element triggering the event and query its subtree to address the specific input element for which you intended to increment or decrement the value.
So in your click event handler,$(this)
will be the button triggering the event, and from there you can select its parent form by doing $parent = $(this).closest('form')
and query its children without involving the whole document by doing $parent.find(/*selector*/)
instead of $(/*selector*/)
Here in this example I also made the function addToInput
that will handle the logics in general dealing with the clicked $button
and the amount
to add passed as arguments.
Plus since you were using input type="submit"
for your plus and minus buttons, I changed them to type="button"
so that the form won't be sumitted at each click. Of course if that was your intended behaviour just revert back to original. But yet those two buttons, for each row, were having the same value for the name
attribute and since they belong to the same form, it would be more appropriate to have each one its own name.
[EDIT after @Roko's comment]
As a final note, you were using the attribute field
in your plus and minus buttons to know the name of the input element that they had to address. Now left aside the fact that, as is, in this exact code, it's not needed because there's no ambiguity since it's the only input type=text
and that condition would be enough to fetch it with no added condition. But yet if you wanted to use such a strategy it was more appropriate to use a data attribute instead:
https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes
Since field
is not a valid attribute for that element as for HTML5 specs.
$(document).ready(function() {
const addToInput = ($button, amount) => {
const $parent = $button.closest('form');
//const fieldName = $button.attr('field');
const fieldName = $button.data('field');
const $input = $parent.find(`input[name=${fieldName}]`);
const currentVal = parseInt($input.val());
if (!isNaN(currentVal)) {
$input.val(currentVal amount);
} else {
$input.val(1);
}
}
$('.qtyplus').click(function(e) {
addToInput($(this), 1);
});
$(".qtyminus").click(function(e) {
addToInput($(this), -1);
});
});
input[type="button"]{
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form method='POST' action=''>
<input
type="button"
value="-"
name="minus"
data-field="quantity">
<input type='text' name='quantity' value='1' class='qty form-control' />
<input
type="button"
value=' '
name="plus"
class='qtyplus btn btn-success btn-sm'
data-field='quantity'>
</form>
<form method='POST' action=''>
<input
type="button"
value="-"
name="minus"
data-field="quantity">
<input type='text' name='quantity' value='1' class='qty form-control' />
<input
type="button"
value=' '
name="plus"
class='qtyplus btn btn-success btn-sm'
data-field='quantity'>
</form>
CodePudding user response:
- Use Event delegation using the jQuery's .on() method:
$(".staticParent").on("eventName", ".dynamicChild", fn)
Then refer to the Event delegator parent using$(evt.delegateTarget)
and to the currently clicked button using$(evt.currentTarget)
(is you use Arrow Function(evt) => {
) , or by using$(this)
if you use Regular Functionfunction(evt) {
- Fix the issues in your HTML markup such as attributes (
name
s, duplicatedvalue
, etc). Don't use invalid non-HTML5 attributes. Use data-* attributes if really needed. (Not needed for this code to work) - Prevent your value go negative using
Math.max()
jQuery($ => { // DOM ready and $ alias in scope
$(".cart-items-number").on("click", ".qtyminus, .qtyplus", (evt) => {
const $qty = $(evt.delegateTarget).find(".qty");
const isMinus = $(evt.currentTarget).hasClass("qtyminus");
const valueCurrent = $qty.val() || 0;
const valueChange = isMinus ? -1 : 1;
const value = Math.max(0, valueCurrent valueChange);
$qty.val(value);
});
});
.cart-items-number { display: inline-flex; }
<link
href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"
rel="stylesheet"
type="text/css" />
<form method='POST' action=''>
<button type="button" >-</button>
<input type='text' name='quantity' value='0' class='qty form-control' />
<button type="button" class='qtyplus btn btn-success btn-sm'> </button>
</form>
<form method='POST' action=''>
<button type="button" >-</button>
<input type='text' name='quantity' value='5' class='qty form-control' />
<button type="button" class='qtyplus btn btn-success btn-sm'> </button>
</form>
<script src="//code.jquery.com/jquery.min.js"></script>
- Alternatively, you could use the
input[type=number]
instead, and its native JavaScriptstepUp()
andstepDown()
methods (Read more on MDN)