htmljqueryfilter

How to filter elements more precisely?


When I type something into the filter, for example the letter "B", the result shows me <div class="item" with; Ball, Dinosaur "blue" and Robot.

I would like to know how I can make the filter ignore what is inside <span class="tag" and only search inside the <p class="name", so that the final result is only <divs class="item" with; Ball and Robot

$("#filter").on("keyup", function () {
    var value =$(this).val().toLowerCase();
    $("#box .item").filter(function () {
      $(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
    });
  });
#box {
  width: 300px;
}
.item {
  display: flex;
  align-items: center;
  gap: 5px;
  border: 1px solid;
}
.name {
  text-transform: uppercase;
}
.tag {
  background: silver;
  padding:2px 4px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<input id="filter" type="text" placeholder="Filter..." autocomplete="off">
<div id="box">
  <div class="item">
    <img src="" alt="img.jpg">
    <p class="name">Radio</p>
    <span class="tag">red</span>
  </div>
  <div class="item">
    <img src="" alt="img.jpg">
    <p class="name">Ball</p>
    <span class="tag">red</span>
  </div>
  <div class="item">
    <img src="" alt="img.jpg">
    <p class="name">Dinosaur</p>
    <span class="tag">blue</span>
  </div>
  <div class="item">
    <img src="" alt="img.jpg">
    <p class="name">Robot</p>
    <span class="tag">blue</span>
  </div>
</div>


Solution

  • Example:

    $("#filter").on("input", function () {
      const value = $(this).val().trim().toLowerCase();
      $("#box .item").each(function () {
        const match = $(".name", this).text().toLowerCase().indexOf(value) > -1;
        $(this).toggle(match);
      });
    });
    #box {
      width: 300px;
    }
    .item {
      display: flex;
      align-items: center;
      gap: 5px;
      border: 1px solid;
    }
    .name {
      text-transform: uppercase;
    }
    .tag {
      background: silver;
      padding:2px 4px;
    }
    <input id="filter" type="text" placeholder="Filter..." autocomplete="off">
    <div id="box">
      <div class="item">
        <img src="" alt="img.jpg">
        <p class="name">Radio</p>
        <span class="tag">red</span>
      </div>
      <div class="item">
        <img src="" alt="img.jpg">
        <p class="name">Ball</p>
        <span class="tag">red</span>
      </div>
      <div class="item">
        <img src="" alt="img.jpg">
        <p class="name">Dinosaur</p>
        <span class="tag">blue</span>
      </div>
      <div class="item">
        <img src="" alt="img.jpg">
        <p class="name">Robot</p>
        <span class="tag">blue</span>
      </div>
    </div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

    Alternatively, you could inverse the logic in that, you first each #box .name elements, and then toggle the parent .item using .closest()

    $("#filter").on("input", function () {
      const value = $(this).val().trim().toLowerCase();
      $("#box .name").each(function () {
        const match = $(this).text().toLowerCase().indexOf(value) > -1;
        $(this).closest(".item").toggle(match);
      });
    });
    #box {
      width: 300px;
    }
    .item {
      display: flex;
      align-items: center;
      gap: 5px;
      border: 1px solid;
    }
    .name {
      text-transform: uppercase;
    }
    .tag {
      background: silver;
      padding:2px 4px;
    }
    .hidden {
      display: none;
      color: red;
    }
    <input id="filter" type="text" placeholder="Filter..." autocomplete="off"><br>
    <div id="box">
      <div class="item">
        <img src="" alt="img.jpg">
        <p class="name">Radio</p>
        <span class="tag">red</span>
      </div>
      <div class="item">
        <img src="" alt="img.jpg">
        <p class="name">Ball</p>
        <span class="tag">red</span>
      </div>
      <div class="item">
        <img src="" alt="img.jpg">
        <p class="name">Dinosaur</p>
        <span class="tag">blue</span>
      </div>
      <div class="item">
        <img src="" alt="img.jpg">
        <p class="name">Robot</p>
        <span class="tag">blue</span>
      </div>
    </div>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>

    Also, why use an entire library (jQuery) for such a simple task?

    const lower = (val) => val?.trim().toLowerCase();
    
    function filterItems (val) {
      document.querySelectorAll("#box .name").forEach(function(elName) {
        const match = lower(elName.textContent).includes(lower(val));
        elName.closest(".item").classList.toggle("hidden", !match);
      });
    }
    
    document.querySelector("#filter").addEventListener("input", function () {
      filterItems(this.value);
    });
    #box {
      width: 300px;
    }
    .item {
      display: flex;
      align-items: center;
      gap: 5px;
      border: 1px solid;
    }
    .name {
      text-transform: uppercase;
    }
    .tag {
      background: silver;
      padding:2px 4px;
    }
    .hidden {
      display: none;
      color: red;
    }
    <input id="filter" type="text" placeholder="Filter..." autocomplete="off">
    <div id="box">
      <div class="item">
        <img src="" alt="img.jpg">
        <p class="name">Radio</p>
        <span class="tag">red</span>
      </div>
      <div class="item">
        <img src="" alt="img.jpg">
        <p class="name">Ball</p>
        <span class="tag">red</span>
      </div>
      <div class="item">
        <img src="" alt="img.jpg">
        <p class="name">Dinosaur</p>
        <span class="tag">blue</span>
      </div>
      <div class="item">
        <img src="" alt="img.jpg">
        <p class="name">Robot</p>
        <span class="tag">blue</span>
      </div>
    </div>