Update quantity before cart with + - buttons

Hello everyone,

right now I’m using the little JS snippet from the docs, to update the quantity and the custom option, which works perfectly:

<label>Quantity</label>
<input id="quantity" type="number"></input
<label>Frame color</label>
<select id="frame_color">
  <option value="Black">Black</option>
  <option value="Brown">Brown</option>
  <option value="Gold">Gold</option>
</select>
<button
  id="starry-night"
  class="snipcart-add-item"
  data-item-id="starry-night"
  data-item-price="79.99"
  data-item-url="/paintings/starry-night"
  data-item-description="High-quality replica of The Starry Night by the Dutch post-impressionist painter Vincent van Gogh."
  data-item-image="/assets/images/starry-night.jpg"
  data-item-name="The Starry Night"
  data-item-custom1-name="Frame color"
  data-item-custom1-options="Black|Brown|Gold"
  data-item-custom2-name="Gift note">
  Add to cart
</button>
<script>
const button = document.querySelector('#starry-night')
const quantity = document.querySelector('#quantity')
quantity.addEventListener('change', () => {
  // Sets the default quantity when adding the item
  button.setAttribute('data-item-quantity', quantity.value)
})
const select = document.querySelector('#frame_color')
select.addEventListener('change', () => {
  // Sets the default frame color when adding the item
  button.setAttribute("data-item-custom1-value", select.value)
})
</script>

But my client wants to change the quantity not only with the input number field, but also with a + and - button.
My question is, how do I get to update the input value with those buttons and updte the item before adding to the cart?

Help is much appreciated…

regards,
Timo

Hi there,

You have two things to do to make this work:

  1. Create HTML buttons
  2. Listen to the click on those buttons to change the quantity field

First, let’s add the barebone increment/decrement buttons (there are a few ways to do this, but here is an example):

<button type="button" class="decrement"> - </button>
<button type="button" class="increment"> + </button>

Then, in your script, you can add event listeners, similarly to the one for the quantity field:

const incrementButton = document.querySelector('.increment')
const decrementButton = document.querySelector('.decrement')

incrementButton.addEventListener('click', () => {
	const newQuantity = (parseInt(quantity.value) || 0) + 1
	quantity.value = newQuantity
        button.setAttribute('data-item-quantity', newQuantity)
})
decrementButton.addEventListener('click', () => {
	const newQuantity = (parseInt(quantity.value) || 0) - 1
	quantity.value = newQuantity
        button.setAttribute('data-item-quantity', newQuantity)
})

Of course, this is a simple example, that can be optimized and also take into account edge cases (min/max quantity, etc).

Let me know if this works for you,
Cheers!

hi dominic,

thank you but sadly it doesn’t work. when I click the + button it only inputs the number 1 and don’t sums it up. so if I press the button twice it results in 11 and not 2.

here is my html

<button type="button" id="plus"> + </button>
<input value=""  min="1" max="5" type="number" step="1" name="quantity" id="quantity">
<button type="button" id="minus" > - </button>

and here my script

const button = document.querySelector('#add-to-cart')
                    const quantity = document.querySelector('#quantity')
                    quantity.addEventListener('change', () => {
                        // Sets the default quantity when adding the item
                        button.setAttribute('data-item-quantity', quantity.value)
                    })
                    const select = document.querySelector('#color')
                    select.addEventListener('change', () => {
                        // Sets the default frame color when adding the item
                        button.setAttribute("data-item-custom1-value", select.value)
                    })

                    const plus = document.querySelector('#plus')
                    const minus = document.querySelector('#minus')

                    plus.addEventListener('click', () => {
                        const newQuantity = (quantity.value || 0) + 1
                        quantity.value = newQuantity
                    })

                    minus.addEventListener('click', () => {
                        const newQuantity = (quantity.value || 0) - 1
                        quantity.value = newQuantity
                    })

any more ideas?

regards,
timo

Yes I updated the answer with the missing part : quantity.value needs to be wrapped with parseInt to convert the string value 1 to a number before incrementing or decrementing it.

Hi dominic,

thanks, the value is now incrementing or decrementing. But if I click the buy button, it only set the quantity of 1 to the cart.
For example, if I increment by clicking the + button twice, the number 2 shows in the quantity field, but after click on add to cart button, it only adds the quantity of 1 to the cart.
Still if I change the quantity in the number field it adds the correct quantity to the cart

Hi Timo,

After playing around with this code, the change event listener does not trigger when updating the quantity value with javascript (only when a user changes the value directly). This means we would need to update the button data attribute when we increment or decrement also. I once again updated the code snippet in my answer above.

The important thing to check is if the data-item-quantity updates accordingly when incrementing or decrementing.

Let me know if this works now! :slight_smile:

@dominic

Your new adjustments working perfect! Thanks for your help!

regards,
Timo

hi @dominic

I did find one more problem. If you click the minus-button the value in the input field goes lower than 0, for example -1 -2 and so one. Do have a solution to prevent numbers below 0?

regards,
Timo

Hi Timo
I faced this problem yesterday too :grinning_face_with_smiling_eyes: The solution for me was to add following attribute to the button in HTML: oninput="this.value = Math.abs(this.value)"

Cheerio
Darko

Hey @Timo and @darkotstecktnedri !

Indeed the example is merely that and a lot of frontend validation could be added to better the experience. Instead of Math.abs(), you could also use Math.max() which will take the highest value between numbers (ie: 0 and new input value)