简体   繁体   中英

Using keyup event to apply changes dynamically to multiple elements

I am trying to build a basic JavaScript search functionality. So I have a couple of divs and an input search field:

<div class="notes">
  <div class="firstNote">FIRST NOTE</div>
  <div class="secondNote">SECOND NOTE</div>
  <div class="thirdNote">THIRD NOTE</div>
  <div class="fourthNote">THIRDDD NOTE</div>
  <div class="fifthNote">THIRL NOTE</div>
</div>
<div class="search">
  <input type="text" placeholder="Search...">
</div>

The idea is that when the user types in the search box, it checks what they typed against the innerHTML values of the divs inside the parent notes div. While those values match, it should apply the searched class to those divs where the matching value is found. And then hide all the other divs by giving them display:none . Once it stops finding a match, it should remove the searched class from all the divs and display them all again by giving them display:block .

The trouble is that this works only for the first div it finds where there is a match. I've created a couple of them starting with the letters 'THIR' for testing. If I start typing 'thir', it only shows (ie applies the 'searched' class to) the first div whose text matches (the one with the thirdNote class), but not the other two even though they still also match. Here's the JS code:

const notes = document.querySelectorAll(".notes div");
const search = document.querySelector(".search input");
let count = 0; //detecting the number of times the user typed in the input field

search.addEventListener("keyup", function(e){
    let x = 1; //will use this to compare the values of the search box and the divs
    if(e.which === 16) //if the user presses Shift, don't do anything
      return;
    if(e.which !== 8) //if pressed anything but Backspace, increase the count
      count++;
    else if(e.which === 8 && count >= 1) { // otherwise decrease the count
      count--;
  } 
  const textSearched = this.value; //what the user typed in the searchbox
//if there is no text in the search box, remove the 'searched' class from all the divs, show all of them, and reset x back to 1
  if(count === 0 || textSearched === ""){
    notes.forEach(function(el){
      if(el.style.display === "none")
        el.style.display = "block";
      if(el.classList.contains("searched"))
        el.classList.remove("searched");
    });
    x = 1;
  }
  notes.forEach((body) => {
  //while the search box and the div text values match, and x is not greater than the div text length, add the 'searched' class and increment x
     while(textSearched.substring(0, x).toLowerCase() === body.innerHTML.substring(0, x).toLowerCase() && x <= body.innerHTML.length) {
         body.classList.add("searched");
       x++;
//if count is less than x, it means there is a match. So show all the matching divs, and hide all the other ones
       if(count < x) {
         notes.forEach((el) => {
           if(!el.classList.contains("searched"))
             el.style.display = "none";
           else
             el.style.display = "block";
         });
      }
// if count is equal or greater than x, it means no more matching, so show all the divs and remove the 'searched' class
       else {
        notes.forEach(function(el){
            if(el.style.display === "none")
              el.style.display = "block";
            if(el.classList.contains("searched"))
              el.classList.remove("searched");
        });
       }
     } 
  }); 
});

Here is a working JS Fiddle: https://jsfiddle.net/tpxd5cqm/4/

Thanks!

This is what I'd do: toggle a class on the parent container when matching search elements are detected, and remove the class when there are no matches, or when the input is empty. When the parent class is active, highlight all .searched children, and hide all non- .searched children:

 const container = document.querySelector('.notes'); const notes = [...container.children]; const input = document.querySelector('input'); input.addEventListener('keydown', () => { // Wait for the input field to contain its final value: setTimeout(checkInput); }); const checkInput = () => { const value = input.value.toLowerCase(); const matchingNotes = notes.filter(note => note.textContent.toLowerCase().includes(value)); if (!value || matchingNotes.length === 0) { container.classList.remove('searchActive'); return; } container.classList.add('searchActive'); for (const note of notes) { if (matchingNotes.includes(note)) { note.classList.add('searched'); } else { note.classList.remove('searched'); } } }
 .searchActive > .searched { background-color: yellow; } .searchActive > *:not(.searched) { display: none; }
 <div class="notes"> <div>FIRST NOTE</div> <div>SECOND NOTE</div> <div>THIRD NOTE</div> <div>THIRDDD NOTE</div> <div>THIRL NOTE</div> </div> <div> <input type="text" placeholder="Search..."> </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM