Home > Software engineering >  Why is dataset undefined sometimes?
Why is dataset undefined sometimes?

Time:08-29

Why is const filter undefined sometimes when i press it..I have used data-filter on buttons to sort store items..but sometimes when i press a button with dataset filter i get undefined

const buttons = document.querySelectorAll('.filter-btn');
const storeItems = document.querySelectorAll('.store-item');

buttons.forEach((button) => {
  button.addEventListener('click', (e) => {
    e.preventDefault()

    const filter = e.target.dataset.filter
    console.log(filter)

    storeItems.forEach((item) => {
      if (filter === 'all') {
        item.style.display = 'block'
      } else {
        if (item.classList.contains(filter)) {
          item.style.display = 'block'
        } else {
          item.style.display = 'none'
        }
      }
    })
  })
})
.img-wrap img {
  width : 300px;
  }
<div >
  <div >
    <h1>OUR <span>STORE</span></h1>

    <div >
      <button data-filter="all" ><p>ALL</p></button>
      <button data-filter="cakes" ><p>CAKES</p></button>
      <button data-filter="cupcakes" ><p>CUPCAKES</p></button>
      <button data-filter="sweets" ><p>SWEETS</p></button>
      <button data-filter="doughnuts" ><p>DOUGHNUTS</p></button>
    </div>
    <div >
      <div >
        <i ></i>
      </div>
      <input type="text" placeholder="Item...">
    </div>
  </div>
  <div >
    <div  data-item="cupcakes">
      <div >
        <img src="https://images.unsplash.com/photo-1614707267537-b85aaf00c4b7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80" alt="">
        <i ></i>
      </div>
      <div >
        <h3>Cupcake</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div  data-item="cupcakes">
      <div >
        <img src="https://images.unsplash.com/photo-1603532648955-039310d9ed75?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80" alt="">
        <i ></i>
      </div>
      <div >
        <h3>Cupcake</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div  data-item="cakes">
      <div >
        <img src="https://images.unsplash.com/photo-1578985545062-69928b1d9587?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1089&q=80" alt="">
        <i ></i>
      </div>
      <div >
        <h3>Cake</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div  data-item="sweets">
      <div >
        <img src="https://images.unsplash.com/photo-1600359756098-8bc52195bbf4?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=688&q=80" alt="">
        <i ></i>
      </div>
      <div >
        <h3>Sweets</h3>
        <h3>$5</h3>
      </div>
    </div>

  </div>
  <div >
    <div  data-item="doughnuts">
      <div >
        <img src="https://images.unsplash.com/photo-1533910534207-90f31029a78e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80" alt="">
        <i ></i>
      </div>
      <div >
        <h3>Doughnuts</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div  data-item="cakes">
      <div >
        <img src="https://images.unsplash.com/photo-1602351447937-745cb720612f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=686&q=80" alt="">
        <i ></i>
      </div>
      <div >
        <h3>Cake</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div  data-item="cupcakes">
      <div >
        <img src="https://images.unsplash.com/photo-1615837136007-701de6015cfb?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80" alt="">
        <i ></i>
      </div>
      <div >
        <h3>Cupcakes</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div  data-item="sweets">
      <div >
        <img src="https://images.unsplash.com/photo-1600359746315-119f1360d663?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=688&q=80" alt="">
        <i ></i>
      </div>
      <div >
        <h3>Sweets</h3>
        <h3>$5</h3>
      </div>
    </div>
  </div>
</div>

CodePudding user response:

The problem is occoured for event deligation. You have a p tag in button. So, for event deligatoin, sometimes click goes to the p tag instead of button. You can fix the issue in this way-

const filter = e.target.closest("button").dataset.filter

CodePudding user response:

e.target will refer to the innermost item clicked. If you add an event listener to the container, and the container has a child element, e.target may refer to the container (if you clicked outside the child), or it may refer to the child (if you clicked inside the child). That's what's happening here. If you click directly on one of the texts inside the button, you'll be clicking on a <p> tag, not the button - and that'll be the target.

<button data-filter="all" ><p>ALL</p></button>
                                             ^^^^^^^^^^

Refer to the button you already have in scope instead of to e.target.

const buttons = document.querySelectorAll('.filter-btn');
const storeItems = document.querySelectorAll('.store-item');

buttons.forEach((button) => {
  button.addEventListener('click', (e) => {
    e.preventDefault()

    const { filter } = button.dataset;
    console.log(filter)

    storeItems.forEach((item) => {
      if (filter === 'all') {
        item.style.display = 'block'
      } else {
        if (item.classList.contains(filter)) {
          item.style.display = 'block'
        } else {
          item.style.display = 'none'
        }
      }
    })
  })
})
.img-wrap img {
  width : 300px;
  }
<div >
  <div >
    <h1>OUR <span>STORE</span></h1>

    <div >
      <button data-filter="all" ><p>ALL</p></button>
      <button data-filter="cakes" ><p>CAKES</p></button>
      <button data-filter="cupcakes" ><p>CUPCAKES</p></button>
      <button data-filter="sweets" ><p>SWEETS</p></button>
      <button data-filter="doughnuts" ><p>DOUGHNUTS</p></button>
    </div>
    <div >
      <div >
        <i ></i>
      </div>
      <input type="text" placeholder="Item...">
    </div>
  </div>
  <div >
    <div  data-item="cupcakes">
      <div >
        <img src="https://images.unsplash.com/photo-1614707267537-b85aaf00c4b7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80" alt="">
        <i ></i>
      </div>
      <div >
        <h3>Cupcake</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div  data-item="cupcakes">
      <div >
        <img src="https://images.unsplash.com/photo-1603532648955-039310d9ed75?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80" alt="">
        <i ></i>
      </div>
      <div >
        <h3>Cupcake</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div  data-item="cakes">
      <div >
        <img src="https://images.unsplash.com/photo-1578985545062-69928b1d9587?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1089&q=80" alt="">
        <i ></i>
      </div>
      <div >
        <h3>Cake</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div  data-item="sweets">
      <div >
        <img src="https://images.unsplash.com/photo-1600359756098-8bc52195bbf4?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=688&q=80" alt="">
        <i ></i>
      </div>
      <div >
        <h3>Sweets</h3>
        <h3>$5</h3>
      </div>
    </div>

  </div>
  <div >
    <div  data-item="doughnuts">
      <div >
        <img src="https://images.unsplash.com/photo-1533910534207-90f31029a78e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80" alt="">
        <i ></i>
      </div>
      <div >
        <h3>Doughnuts</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div  data-item="cakes">
      <div >
        <img src="https://images.unsplash.com/photo-1602351447937-745cb720612f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=686&q=80" alt="">
        <i ></i>
      </div>
      <div >
        <h3>Cake</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div  data-item="cupcakes">
      <div >
        <img src="https://images.unsplash.com/photo-1615837136007-701de6015cfb?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80" alt="">
        <i ></i>
      </div>
      <div >
        <h3>Cupcakes</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div  data-item="sweets">
      <div >
        <img src="https://images.unsplash.com/photo-1600359746315-119f1360d663?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=688&q=80" alt="">
        <i ></i>
      </div>
      <div >
        <h3>Sweets</h3>
        <h3>$5</h3>
      </div>
    </div>
  </div>
</div>

If you had to gain another reference to the element you attached the event listener to and didn't have button already in scope, you could use e.currentTarget instead of e.target - .target will refer to the innermost element (the one that the event was dispatched to), but e.currentTarget will refer to the element the listener is attached to.

  • Related