Input Quantity Button Plus and Minus

How to change quantity with plus minus buttons with plain Javascript

This should do the trick.

let plus_btns = document.querySelectorAll('#plus-button');
let minus_btns = document.querySelectorAll('#minus-button');
let qty_inputs = document.querySelectorAll('#quantity');

plus_btns.forEach(btn=>{
btn.addEventListener('click', ()=>{
btn.previousElementSibling.value++;
})
})
minus_btns.forEach(btn=>{
btn.addEventListener('click', ()=>{
btn.nextElementSibling.value = (btn.nextElementSibling.value == 0) ? 0 : btn.nextElementSibling.value - 1;
})
})

How to create a total using plus minus buttons and input box

  • Change the event to 'input' so it only fires for actual value changes
  • Add trigger('input') to the end of the value changes so the event is generated (logical value changes do not generate events).
  • Move the first bindings into the document ready for safety (optional change).
  • Put Math.max() around the subtraction so that the negative can not make the value go less than zero. (optional change)

/*For total*/$(document).ready(function() {  $(".checkout").on("input", ".quantity", function() {    var price = +$(".price").data("price");    var quantity = +$(this).val();    $("#total").text("$" + price * quantity);  })
var $buttonPlus = $('.increase-btn'); var $buttonMin = $('.decrease-btn'); var $quantity = $('.quantity'); /*For plus and minus buttons*/ $buttonPlus.click(function() { $quantity.val(parseInt($quantity.val()) + 1).trigger('input'); }); $buttonMin.click(function() { $quantity.val(Math.max(parseInt($quantity.val()) - 1, 0)).trigger('input'); });})
.checkout {  height: 300px;  width: 400px;  margin: 20px auto;  border: 2px solid black;  text-align: center;}
<head>  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script></head><div class="checkout">  <h1 class="title">Checkout</h1>  <p class="price" data-price="21">$21 per month</p>  <p class="description">Quantity:</p>  <button type="button" class="decrease-btn">-</button>  <input type="text" class="quantity" value="1">  <button type="button" class="increase-btn">+</button>  <p class="total">Total: <span id="total">$21</span></p></div>

How to get plus minus to update button text

Just call updateGuests() in your increment and decrement functions. You were 99% there.

I'd encourage you to move away from jQuery. You're halfway there with this code anyway, and it's a crutch against robust learning of JavaScript. These operations are simple enough that you just don't need it. See https://youmightnotneedjquery.com.

var adultModal = document.getElementById("adultModal");
var adultBtn = document.getElementById("guests");
var adultSpan = document.getElementsByClassName("adultClose")[0];

adultBtn.onclick = function() {
adultModal.style.display = "block";
}

adultSpan.onclick = function() {
adultModal.style.display = "none";
}

window.onclick = function(event) {
if (event.target == adultModal) {
adultModal.style.display = "none";
}
}

// NUMBER FIELD PLUS / MINUS SCRIPT

function incrementValue(e) {
e.preventDefault();
var fieldName = $(e.target).data('field');
var parent = $(e.target).closest('div');
var currentVal = parseInt(parent.find('input[name=' + fieldName + ']').val(), 10);

if (!isNaN(currentVal)) {
parent.find('input[name=' + fieldName + ']').val(currentVal + 1);
} else {
parent.find('input[name=' + fieldName + ']').val(0);
}

updateGuests();
}

function decrementValue(e) {
e.preventDefault();
var fieldName = $(e.target).data('field');
var parent = $(e.target).closest('div');
var currentVal = parseInt(parent.find('input[name=' + fieldName + ']').val(), 10);

if (!isNaN(currentVal) && currentVal > 0) {
parent.find('input[name=' + fieldName + ']').val(currentVal - 1);
} else {
parent.find('input[name=' + fieldName + ']').val(0);
}

updateGuests();
}

$('.input-group').on('click', '.button-plus', function(e) {
incrementValue(e);
});

$('.input-group').on('click', '.button-minus', function(e) {
decrementValue(e);
});

function updateGuests() {
let adultNumb = document.getElementById("adultQuantity");
let produceAdult = document.getElementById('adultValue');
produceAdult.innerHTML = adultNumb.value;

let childNumb = document.getElementById("childQuantity");
let produceChild = document.getElementById('childValue');
produceChild.innerHTML = childNumb.value;
}
/* The Modal (background) */

.modal {
display: none;
/* Hidden by default */
position: fixed;
/* Stay in place */
z-index: 1;
/* Sit on top */
padding-top: 100px;
/* Location of the box */
left: 0;
top: 0;
width: 100%;
/* Full width */
height: 100%;
/* Full height */
overflow: auto;
/* Enable scroll if needed */
}


/* Modal Content */

.modal-content {
background-color: #fefefe;
margin: auto;
padding: 5px 20px;
border: 1px solid #888;
width: 280px;
position: relative;
}


/* The Close Button */

.adultClose,
.childClose {
color: #aaaaaa;
position: absolute;
right: 5px;
top: 0px;
font-size: 22px;
font-weight: bold;
cursor: pointer;
}

.close:hover,
.close:focus {
color: #000;
text-decoration: none;
cursor: pointer;
}


/* INPUT NUMBER PLUS/MINUS BUTTONS */

input,
textarea {
border: 1px solid #eeeeee;
box-sizing: border-box;
margin: 0;
outline: none;
padding: 10px;
}

input[type="button"] {
-webkit-appearance: button;
cursor: pointer;
}

input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
}

.input-group {
clear: both;
margin: 15px 0;
position: relative;
}

.input-group input[type='button'] {
background-color: #eeeeee;
min-width: 38px;
width: auto;
transition: all 300ms ease;
}

.input-group .button-minus,
.input-group .button-plus {
font-weight: bold;
height: 38px;
padding: 0;
width: 38px;
position: relative;
}

.input-group .quantity-field {
position: relative;
height: 38px;
left: -6px;
text-align: center;
width: 62px;
display: inline-block;
font-size: 13px;
margin: 0 0 5px;
resize: vertical;
}

.button-plus {
left: -13px;
}

input[type="number"] {
-moz-appearance: textfield;
-webkit-appearance: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<h3>Guests</h3>
<button id="guests" type="button" class="adults">
<span class="bw-toggle__value"><span id="adultValue">2</span> Adults <span class="bw-divide">/</span> <span id="childValue">0</span> Children</span>
</button>


<!-- Adult Modal -->
<div id="adultModal" class="modal">
<!-- Modal content -->
<div class="modal-content">
<span class="adultClose">×</span>
<div class="input-group">
ADULTS
<input type="button" value="-" class="button-minus" data-field="quantity">
<input type="number" step="1" max="" value="2" name="quantity" class="quantity-field" id="adultQuantity" onchange="updateGuests()">
<input type="button" value="+" class="button-plus" data-field="quantity">
</div>
<div class="input-group">
CHILDREN
<input type="button" value="-" class="button-minus" data-field="quantity">
<input type="number" step="1" max="" value="0" name="quantity" class="quantity-field" id="childQuantity" onchange="updateGuests()">
<input type="button" value="+" class="button-plus" data-field="quantity">
</div>
</div>
</div>

Plus/Minus a quantity field

There are some other issues (besides incorrect element-query) here:

  • to select a CSS-class use a dot before class name: e.g. .btn-minus
  • to get or set the value of an input control use its value property: quantityNumber.value += 1 (even decrement/increment: e.g. quantityNumber.value++)
  • if you first set the variable currentValue to (constant!) 1 and use in de-/increment then state is UI-independent. The user might initially enter 5 in the input-field then hitting the plus-button when your listener changes to 1+1=2.
  • CSS-classes for referencing form-controls may work on all controls (independent of the current context). If you have product-specific quantity then the use-case might be to enter different quantities for different products/order-lines. So working with an element ID may be an alternative.
  • there is already a HTML number input, which supports these operations stepUp/stepDown as well as min/max (see B in example below)
  • there may be a minimum-quantity (e.g. 0) allowed: use HTML input-field's min property and/or conditionally disable minus-button

// product Avar minus_A = document.querySelector("#product_A_form .btn-subtract")var add_A = document.querySelector("#product_A_form .btn-add");var quantity_A = document.querySelector("#product_A_form .item-quantity");
minus_A.addEventListener("click", function(){ quantity_A.value--;});
add_A.addEventListener("click", function() { quantity_A.value++;});
// product Bvar minus_B = document.querySelector("#product_B_form .btn-subtract")var add_B = document.querySelector("#product_B_form .btn-add");var quantity_B = document.querySelector("#product_B_form .item-quantity");
// includes button minus disablement if at minimum or belowconst minimum = 0;
minus_B.addEventListener("click", function(){ if (quantity_B.value <= minimum) { minus_B.disabled = true; return; // return to avoid decrementing } else { minus_B.disabled = false; } quantity_B.value--;});
add_B.addEventListener("click", function() { if (quantity_B.value > minimum) { minus_B.disabled = false; } quantity_B.value++;});
<!-- product A --><div id="product_A_form" class="input-group">  A  <span class="input-group-btn">    <button class="btn btn-default btn-subtract" type="button">-</button>  </span>
<input id="product_A_qty" type="text" class="form-control no-padding text-center item-quantity" value="1">
<span class="input-group-btn"> <button class="btn btn-default btn-add" type="button">+</button> </span></div>
<!-- product B --><div id="product_B_form" class="input-group"> B <span class="input-group-btn"> <button class="btn btn-default btn-subtract" type="button">-</button> </span>
<input type="number" class="form-control no-padding text-center item-quantity" min="0" value="1">
<span class="input-group-btn"> <button class="btn btn-default btn-add" type="button">+</button> </span></div>

Issue with plus/minus quantity buttons

Here is a forked fiddle with it working.

Your issue is in the form itself and the selector:

<form id='myform' method='POST' action='#'>
<input type='button' value='-' class='qtyminus' field='quantity' />
<input type='text' name='quantity' value='0' class='qty' />
<input type='button' value='+' class='qtyplus' field='quantity' />
</form>
<form id='myform2' method='POST' action='#'>
<input type='button' value='-' class='qtyminus' field='quantity' />
<input type='text' name='quantity' value='0' class='qty' />
<input type='button' value='+' class='qtyplus' field='quantity' />
</form>

When you do a jquery selector of $('input[name='+fieldName+']') it is returning every element that matches that condition and both of your forms have a field with that name.

Use parent() to find the parent form element, then a find to search only in that context and you'll see this works as intended:

var currentVal = parseInt($(this).parent().find('input[name='+fieldName+']').val());
// If is not undefined
if (!isNaN(currentVal)) {
// Increment
$(this).parent().find('input[name='+fieldName+']').val(currentVal + 1);
} else {
// Otherwise put a 0 there
$(this).parent().find('input[name='+fieldName+']').val(0);
}

Using closest() would have only gone back UP the document hierarchy, so it had no chance of finding a sibling element. You could also have used the siblings function to identify the desired elements.

How to get the quantity value to update when plus and minus buttons are clicked and their functions are called

I tested your code and it worked well but it won't work with multiple inputs since you would be using the same variables. If your code doesn't work and your html is exactly like the on you posed, the issue might be in the link between your html and your javascript code. Do you have something like <script src="myscripts.js"></script> in your html ? This page might help you: https://www.w3schools.com/tags/att_script_src.asp

If not, here's an example that works with multiple inputs:

function plus(elem){    let targetElem = elem.parentNode.previousElementSibling.childNodes[0];    let targetCount = parseInt(targetElem.value);    targetCount++;    targetElem.value = targetCount;}function minus(elem){    let targetElem = elem.parentNode.nextElementSibling.childNodes[0];    let targetCount = parseInt(targetElem.value);    if (targetCount > 1) {        targetCount--;        targetElem.value = targetCount;    }}
<c:forEach var = "row" items = "${result.rows}">        <tr>            <td><c:out value = "${row.gift_code}"/></td>            <td><c:out value = "£${row.price}"/></td>            <td><c:out value = "${row.stock}"/></td>            <td><div id="outer">                <div><button type="button" name="button"onclick="minus(this)"><img src="minus.jpg" alt="minus"/></button></div>                <div><input type="text" name="name" value="1" size="10" id="count1"></div>                <div><button type="button" name="button"onclick="plus(this)"><img src="plus.jpg" alt="plus"/></button></div>                                                <div><button type="button" name="button"onclick="minus(this)"><img src="minus.jpg" alt="minus"/></button></div>                <div><input type="text" name="name" value="1" size="10" id="count2"></div>                <div><button type="button" name="button"onclick="plus(this)"><img src="plus.jpg" alt="plus"/></button></div>                </div>            </td>            <td>                <form action="order.jsp" method="GET">                    <input type = "hidden" name = "gift_code"                           value = "${row.gift_code}" />                    <input type = "hidden" name = "price"                           value = "${row.price}" />                    <input type = "submit" value = "Add to giftlist" />                    <input type = "hidden" name = "stock"                           value = "${row.stock}" />
</form> </td> </tr>
</c:forEach>

Custom plus and minus quantity buttons in Woocommerce 3

Your First code part is made from a customization of global/quantity-input.php Woocommerce template code…

So for testing, I have changed partially that global/quantity-input.php template code with the following (very near to your code):

?>
<div class="quantity">
<label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php esc_html_e( 'Quantity', 'woocommerce' ); ?></label>
<input type="button" value="-" class="qty_button minus" />
<input
type="number"
id="<?php echo esc_attr( $input_id ); ?>"
class="input-text qty text"
step="<?php echo esc_attr( $step ); ?>"
min="<?php echo esc_attr( $min_value ); ?>"
max="<?php echo esc_attr( 0 < $max_value ? $max_value : '' ); ?>"
name="<?php echo esc_attr( $input_name ); ?>"
value="<?php echo esc_attr( $input_value ); ?>"
title="<?php echo esc_attr_x( 'Qty', 'Product quantity input tooltip', 'woocommerce' ); ?>"
size="4"
pattern="<?php echo esc_attr( $pattern ); ?>"
inputmode="<?php echo esc_attr( $inputmode ); ?>"
aria-labelledby="<?php echo esc_attr( $labelledby ); ?>" />
<input type="button" value="+" class="qty_button plus" />
</div>
<?php

Now the necessary CSS and revisited jQuery code functions:

// Minimum CSS to remove +/- default buttons on input field type number
add_action( 'wp_head' , 'custom_quantity_fields_css' );
function custom_quantity_fields_css(){
?>
<style>
.quantity input::-webkit-outer-spin-button,
.quantity input::-webkit-inner-spin-button {
display: none;
margin: 0;
}
.quantity input.qty {
appearance: textfield;
-webkit-appearance: none;
-moz-appearance: textfield;
}
</style>
<?php
}


add_action( 'wp_footer' , 'custom_quantity_fields_script' );
function custom_quantity_fields_script(){
?>
<script type='text/javascript'>
jQuery( function( $ ) {
if ( ! String.prototype.getDecimals ) {
String.prototype.getDecimals = function() {
var num = this,
match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
if ( ! match ) {
return 0;
}
return Math.max( 0, ( match[1] ? match[1].length : 0 ) - ( match[2] ? +match[2] : 0 ) );
}
}
// Quantity "plus" and "minus" buttons
$( document.body ).on( 'click', '.plus, .minus', function() {
var $qty = $( this ).closest( '.quantity' ).find( '.qty'),
currentVal = parseFloat( $qty.val() ),
max = parseFloat( $qty.attr( 'max' ) ),
min = parseFloat( $qty.attr( 'min' ) ),
step = $qty.attr( 'step' );

// Format values
if ( ! currentVal || currentVal === '' || currentVal === 'NaN' ) currentVal = 0;
if ( max === '' || max === 'NaN' ) max = '';
if ( min === '' || min === 'NaN' ) min = 0;
if ( step === 'any' || step === '' || step === undefined || parseFloat( step ) === 'NaN' ) step = 1;

// Change the value
if ( $( this ).is( '.plus' ) ) {
if ( max && ( currentVal >= max ) ) {
$qty.val( max );
} else {
$qty.val( ( currentVal + parseFloat( step )).toFixed( step.getDecimals() ) );
}
} else {
if ( min && ( currentVal <= min ) ) {
$qty.val( min );
} else if ( currentVal > 0 ) {
$qty.val( ( currentVal - parseFloat( step )).toFixed( step.getDecimals() ) );
}
}

// Trigger change event
$qty.trigger( 'change' );
});
});
</script>
<?php
}

Code goes in function.php file of your active child theme (or active theme). Tested and works.

The quantity buttons "plus" and "minus" work perfectly and are displayed this way:

Sample Image

Products are added to cart with the correct quantity:

Sample Image

if you change the quantity field value with plus and minus buttons, the "Update cart" button is activated when any quantity field change.

Sample Image

When you click on "Update cart", the quantities as correctly updated.

Plus / Minus product with button

You need to do what your code does for each .quantity group.

But there are a couple of errors in your html

  • you try to access the .input-btn which is not applied to any element
  • you try to set currentValue to 0 after declaring a const when you should try to set the input field to 0
  • you are using the same id for the button/inputs of each .quantity group which is invalid.

so

const quantities = document.querySelectorAll('.quantity');
[...quantities].forEach(function(quantity) { const minusButton = quantity.querySelector('.minus-btn'); const plusButton = quantity.querySelector('.plus-btn'); const inputField = quantity.querySelector('.input-btn');
minusButton.addEventListener('click', function minusProduct() { const currentValue = Number(inputField.value); if (currentValue > 0) { inputField.value = currentValue - 1; } else inputField.value = 0 });
plusButton.addEventListener('click', function plusProduct() { const currentValue = Number(inputField.value); inputField.value = currentValue + 1; });
});
<!-- Product #1 --><div class="quantity">  <button class="plus-btn" type="button" name="button"><img src="plus.svg" alt="Sample Image" /></button>  <input type="text" value="0" class="input-btn" />  <button class="minus-btn" type="button" name="button"><img src="minus.svg" alt="Sample Image" /></button></div>
<!-- Product #2 --><div class="quantity"> <button class="plus-btn" type="button" name="button"><img src="plus.svg" alt="Sample Image" /></button> <input type="text" value="0" class="input-btn" /> <button class="minus-btn" type="button" name="button"><img src="minus.svg" alt="Sample Image" /></button></div>
<!-- Product #3 --><div class="quantity"> <button class="plus-btn" type="button" name="button"><img src="plus.svg" alt="Sample Image" /></button> <input type="text" value="0" class="input-btn" /> <button class="minus-btn" type="button" name="button"><img src="minus.svg" alt="Sample Image" /></button></div>


Related Topics



Leave a reply



Submit