I am currently developing a quantity selector feature for an online store. The quantity selector includes:
- The minus button
- The quantity input field: whenever the user clicks on either the plus or minus buttons, the value is updated
- The quantity text: this is the quantity enclosed in
<span>
tags - The plus button
Below is the HTML structure for the quantity selector:
<div class="product-form__input product-form__quantity">
<label class="form__label">
Quantity
</label>
<button class="quantity__button minus no-js-hidden" name="minus" type="button" disabled>
-
</button>
<input class="quantity__input"
type="number"
name="quantity"
id="Quantity-{{ section.id }}"
min="1"
value="1"
form="{{ product_form_id }}"
>
<span class="quantity__text">1</span>
<button class="quantity__button plus" name="plus" type="button">
+
</button>
</div>
The JavaScript code for this functionality is as follows, where the quantityPicker.init()
function is invoked:
- Updating the quantity input field's value each time the user interacts with the plus or minus buttons (calling the
quantityPicker.onButtonClick()
method) - If the quantity input field's value changes, then triggering the
quantityPicker.onChange()
function.
// Quantity picker
let
quantityFields = document.querySelectorAll(".quantity__input"),
quantityButtons = document.querySelectorAll(".quantity__button"),
quantityPicker = {
// Function to handle button clicks
onButtonClick: function (event) {
let
button = event.target,
picker = button.closest(".product-form__quantity"),
quantity = picker.querySelector(".quantity__input"),
quantityValue = parseInt(quantity.value),
max = quantity.getAttribute("max") ? parseInt(quantity.getAttribute("max")) : null
if (button.classList.contains("plus") && (max === null || quantityValue + 1 <= null)) {
quantity.value = quantityValue + 1
}
else if (button.classList.contains("minus")) {
quantity.value = quantityValue - 1
}
},
// Function to handle input field changes
onChange: function (event) {
let
field = event.target,
picker = field.closest(".product-form__quantity"),
quantityText = picker.querySelector(".quantity__text"),
shouldDisableMinus = parseInt(event.target.value) === parseInt(field.getAttribute("min")),
shouldDisablePlus = parseInt(event.target.value) === parseInt(field.getAttribute("max")),
minusButton = picker.querySelector(".quantity__button.minus"),
plusButton = picker.querySelector(".quantity__button.plus")
quantityText.innerText = event.target.value
if (shouldDisableMinus) {
minusButton.setAttribute("disabled", "disabled")
} else if (minusButton.getAttribute("disabled") === true) {
minusButton.removeAttribute("disabled")
}
if (shouldDisablePlus) {
plusButton.setAttribute("disabled", "disabled")
} else if (plusButton.getAttribute("disabled") === true) {
plusButton.removeAttribute("disabled")
}
},
// Initialize the quantity picker
init: function () {
// Handle button click events
quantityButtons.forEach(quantityButton => {
quantityButton.addEventListener("click", function (event) {
quantityPicker.onButtonClick(event)
})
})
// Handle input field change events
console.log(quantityFields)
quantityFields.forEach(quantityField => {
console.log(quantityField)
quantityField.addEventListener("change", function (event) {
console.log("Value changed!")
quantityPicker.onChange(event);
})
})
}
}
quantityPicker.init()
However, there seems to be an issue where the change
event does not trigger when clicking on the plus or minus buttons, only when directly typing into the input and submitting by pressing Enter. How can we ensure that the quantityPicker.onChange()
function executes every time the value updates without requiring the user to press Enter?