3

I'm trying to create two numerical inputs, each of which has their own custom '+' and '-' buttons. However, with my current code, it appears that the button functions only work some of the time. On the other occasions I get a Uncaught TypeError: Cannot read properties of null (reading 'value') at HTMLButtonElement.<anonymous> error.

This is the HTML:

<div class="col">
    <div class="row">
        <div class="input-group mx-auto w-50">
            <div class="input-group-prepend">
                <button class="btn btn-dark btn-sm minus" data-id="one"
                    type="button"><i class="fa fa-minus"></i></button>
            </div>
            <input type="number" id="one" 
                class="form-control form-control-sm text-center" value="0">
            <div class="input-group-prepend">
                <button class="btn btn-dark btn-sm plus" data-id="one" type="button"><i
                        class="fa fa-plus"></i></button>
            </div>
        </div>
    </div>

    <div class="row">
        <div class="input-group mx-auto w-50">
            <div class="input-group-prepend">
                <button class="btn btn-dark btn-sm minus" data-id="two"
                    type="button"><i class="fa fa-minus"></i></button>
            </div>
            <input type="number" id="two"
                class="form-control form-control-sm text-center" value="0">
            <div class="input-group-prepend">
                <button class="btn btn-dark btn-sm plus" data-id="two" type="button"><i
                        class="fa fa-plus"></i></button>
            </div>
        </div>
    </div>
</div>

And this is the Javascript:

<script>
document.addEventListener("DOMContentLoaded", () => {
    document.querySelectorAll('.minus').forEach(item => {
        item.addEventListener('click', event => {
            var input_id = event.target.getAttribute('data-id')
            console.log('Minus button clicked for input ' + input_id)
            var quantityInput = document.getElementById(input_id);
            var currentQuantity = parseInt(quantityInput.value);
            quantityInput.value = currentQuantity - 1
        })
    })
    document.querySelectorAll('.plus').forEach(item => {
        item.addEventListener('click', event => {

            var input_id = event.target.getAttribute('data-id')
            console.log('Plus button clicked for input ' + input_id)
            var quantityInput = document.getElementById(input_id);
            var currentQuantity = parseInt(quantityInput.value);
            quantityInput.value = currentQuantity + 1
        })
    })
})

Here is a sample of the output after clicking a few of the buttons:

Sample output after clicking a few buttons

Shamil Jamion
  • 183
  • 10
  • 1
    If you have difficulty with type errors like this, consider using typescript – Tim Grant Jul 18 '22 at 00:06
  • 2
    Possible duplicate of [What is the exact difference between currentTarget property and target property in JavaScript](https://stackoverflow.com/questions/10086427/what-is-the-exact-difference-between-currenttarget-property-and-target-property) – Ivar Jul 18 '22 at 00:17

2 Answers2

4

The event.target may be the span inside the button, and therefore the code may not find the data-id attribute. Instead perhaps get the id without using event.target. Either use item or event.currentTarget.

dqhendricks
  • 19,030
  • 11
  • 50
  • 83
2

the click event happend on the <i class="fa fa-minus"></i>
you may use Event.currentTarget instead of event.target

document.addEventListener("DOMContentLoaded", () =>
  {
  document.querySelectorAll('.minus').forEach(item =>
    {
    item.onclick = event => 
      {
      let
        input_id        = event.currentTarget.dataset.id
      , quantityInput   = document.getElementById(input_id)
      , currentQuantity = parseInt(quantityInput.value)
        ;
      console.log('Minus button clicked for input ' + input_id)
      quantityInput.value = currentQuantity - 1
      }
    })
  document.querySelectorAll('.plus').forEach(item =>
    {
    item.onclick = event => 
      {
      let
        input_id        = event.currentTarget.dataset.id
      , quantityInput   = document.getElementById(input_id)
      , currentQuantity = parseInt(quantityInput.value)
        ;
      console.log('Plus button clicked for input ' + input_id)
      quantityInput.value = currentQuantity + 1
      }
    })
  })

you can also simply do:

document.addEventListener("DOMContentLoaded", () =>
  {
  document
    .querySelectorAll('button.minus, button.plus')     
    .forEach( btn =>              // this is the button
    {
    btn.onclick = () =>         // no event argument needed
      {
      let
        input_Qte = document.getElementById( btn.dataset.id ) 
      , adding    = btn.classList.contains('plus') ? +1 : -1
        ;
      input_Qte.value = +input_Qte.value + adding   // use +input_Qte.value for integer conversion
      }
    })
  })
Mister Jojo
  • 20,093
  • 6
  • 21
  • 40