0

There is a searchable bar for cards heading in below snippet. It is highlighting the searched value in headings of cards

Can it be possible to count the number of cards having search value . Like I search for "pro" than it show "Result for pro is in 4 cards " . Whatever I search in bar than it show the number of cards having the searched value .
Example : Let say I typed "p" or "pro" in search bar than check in how many cards "p" or "pro" is used and count the number near search bar . Here "pro" is used in 4 cards so 4 will be displayed and "p" is used in 5 cards so 5 will be displayed

Also there is problem in program that when search for "yatch", it is showing "No result found for "yatch" " because I used the indexOf to check if it is available or not but still showing not found even if it is there and highlighting it .
Try to type "yatch" in search . It will highlight "yatch" but also show not found near search bar.

document.getElementById("search").addEventListener("input", refree);

function refree() {
  var reader = document.getElementsByClassName("deviceNameCardHead")
  for (let i = 0; i < reader.length; i++) {
    var readerText = reader[i].textContent
    var reed = document.getElementById("search").value;
    var reed1 = reed.toLowerCase();
    if (reed != '') {
      reader[i].innerHTML = readerText.replace(new RegExp(reed, 'gi'), (match) => `<span class="highlight">${match}</span>`);
      if (readerText.toLowerCase().indexOf(reed1) > -1) {
        reader[i].parentElement.style.display = "block";
        document.getElementById("demo").innerHTML = "Showing " + "10(The number of cards showing the searched word) results" + " for <b>\"" + reed + "\"</b>";
      } else {
        reader[i].parentElement.style.display = "none";
        document.getElementById("demo").innerHTML = "No result found for <b>\"" + reed + "\"</b>";
      }
    } else {
      reader[i].innerHTML = readerText;
      reader[i].parentElement.style.display = "block";
      document.getElementById("demo").innerHTML = "Showing all 5 results";
    }
  }
}
.highlight {
  background: yellow;
}

.deviceNameCardFlex {
  display: flex;
  flex-flow: row;
  flex-wrap: wrap;
  justify-content: flex-start;
}

.deviceNameCard {
  display: flex;
  flex-flow: column;
  border: 2px solid red;
  width: 40%;
  height:200px;
  box-shadow:3px 3px 10px;
  border-radius:5px;
  padding: 10px;
  margin: 10px;
  text-align: center;
}
<div id="devicesBtnData">
  <div class="searchDevice">
    <span class="searchDeviceBtn">Search Device</span>
    <input id="search" type="search" placeholder="Try it">
    <span id="demo"></span>
    <span id="demo1"></span>
    <br>
  </div>

  <div class="deviceNameCardFlex">
    <div class="deviceNameCard">
      <h3 class="deviceNameCardHead">Lenova Yoga laptop Pro</h3>
      <div>Card Content</div>
    </div>
    <div class="deviceNameCard">
      <h3 class="deviceNameCardHead">Lenova Yoga laptop Pro</h3>
      <div>Card Content</div>
    </div>
    <div class="deviceNameCard">
      <h3 class="deviceNameCardHead">No use of P in next</h3>
      <div>Card Content</div>
    </div>
    <div class="deviceNameCard">
      <h3 class="deviceNameCardHead">yatch</h3>
      <div>Card Content</div>
    </div>
    <div class="deviceNameCard">
      <h3 class="deviceNameCardHead">Lenova Yoga laptop Pro</h3>
      <div>Card Content</div>
    </div>

  </div>
</div>
Rana
  • 2,500
  • 2
  • 7
  • 28

1 Answers1

1

You need to mark when you get a match because you should have different behaviours between your elements (the line of text and the highlighting)

There 2 things done in the same loop:

  1. update the items list.
  2. update the text "there's X results or whatever". Problem with the text is that it gets evaluated for each list item but this is not what we want, we want to evaluate the text against the whole list of items, not against each items individually.

What happens in the original code is that you type a match but when the match happens, it gets evaluated on the next iteration of your loop against the last item of your list that is a mismatch.

You can also try to type "next" and it behaves the same as "yatch" because the last element of your list is a mismatch. Try to place the yatch item at the end of your list and it's gonna work only for this one. I'm gonna add logs so you can see what's happening more clearly

document.getElementById("search").addEventListener("input", refree);

function refree() {
  const search = document.getElementById("search").value.toLowerCase();
  const cards = document.getElementsByClassName("deviceNameCardHead");
  let nbMatch = 0;
  // var found = false;
  
  for (let i = 0; i < cards.length; i++) {
    let curCardText = cards[i].textContent;

    if (search !== "") {
      cards[i].innerHTML = curCardText.replace(
        new RegExp(search, "gi"),
        (match) => `<span class="highlight">${match}</span>`
      );
      console.log(`${curCardText.toLowerCase()} == ${search} ?`);
      if (curCardText.toLowerCase().indexOf(search) !== -1) {
      
        console.log("MATCH")
        nbMatch++
        cards[i].parentElement.style.display = "block";
        document.getElementById("demo").innerHTML =
          `Showing ${nbMatch} results for <b> ${search} </b>`;
        
      } else {
        console.log("MISMATCH")
        cards[i].parentElement.style.display = "none";
        if (nbMatch==0)
          document.getElementById("demo").innerHTML =
            'No result found for <b>"' + search + '"</b>';
      }
      console.log('----------------------------------')
    } else {
      cards[i].innerHTML = curCardText;
      cards[i].parentElement.style.display = "block";
      document.getElementById("demo").innerHTML = "Showing all 5 results";
    }
  }
}
body {
  font-family: sans-serif;
}
.highlight {
  background: yellow;
}

.deviceNameCardFlex {
  display: flex;
  flex-flow: row;
  flex-wrap: wrap;
  justify-content: flex-start;
}

.deviceNameCard {
  display: flex;
  flex-flow: column;
  border: 2px solid red;
  width: 40%;
  height: 200px;
  box-shadow: 3px 3px 10px;
  border-radius: 5px;
  padding: 10px;
  margin: 10px;
  text-align: center;
}
<div id="devicesBtnData">
      <div class="searchDevice">
        <span class="searchDeviceBtn">Search Device</span>
        <input id="search" type="search" placeholder="Try it" />
        <span id="demo"></span>
        <span id="demo1"></span>
        <br />
      </div>

      <div class="deviceNameCardFlex">
        <div class="deviceNameCard">
          <h3 class="deviceNameCardHead">Lenova Yoga laptop Pro</h3>
          <div>Card Content</div>
        </div>
        <div class="deviceNameCard">
          <h3 class="deviceNameCardHead">Lenova Yoga laptop Pro</h3>
          <div>Card Content</div>
        </div>
        <div class="deviceNameCard">
          <h3 class="deviceNameCardHead">No use of P in next</h3>
          <div>Card Content</div>
        </div>
        
        <div class="deviceNameCard">
          <h3 class="deviceNameCardHead">Lenova Yoga laptop Pro</h3>
          <div>Card Content</div>
        </div>
        <div class="deviceNameCard">
          <h3 class="deviceNameCardHead">yatch</h3>
          <div>Card Content</div>
        </div>
      </div>
    </div>
Big_Boulard
  • 799
  • 1
  • 13
  • 28
  • What is **found** work here and is `!found` mean false – Rana Sep 11 '21 at 20:57
  • When I try to print index of **yatch** , it prints `-1` what can be the reason of this . Can you tell that plz – Rana Sep 11 '21 at 21:00
  • I've added explanation and logs so you get a deeper insight into what's going on here – Big_Boulard Sep 12 '21 at 06:43
  • Thanks for answer very much , I will upvote it . As I also want to add counter of cards which have searched item , so can't accept as complete answer . Thanks for your time and effort. – Rana Sep 12 '21 at 07:58
  • As you needed a counter, the boolean makes no use anymore. I've also changed you var names to make it a bit more legible. Take note of String Literal (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) and I would advise you to switch to strict mode by including 'use strict' at the 1st line of your JS Files and replace var by let or const to avoid polluting the global scope and getting weird issues. see here for more detail: https://stackoverflow.com/questions/762011/whats-the-difference-between-using-let-and-var – Big_Boulard Sep 12 '21 at 08:35
  • Thanks brother very much . I will try this code and if I face any problem I will ask to you . – Rana Sep 12 '21 at 08:58
  • How to count total number of cards present in screen when nothing is searched . What code did I have to add – Rana Sep 12 '21 at 10:32
  • Also can you tell about `replace(new RegExp(search, "gi"),(match) =>` `${match}` );` . Here what `match` is doing , it is my first time use – Rana Sep 12 '21 at 10:34
  • The 1st argument of the replace function takes the regex (or string) to search, then the 2nd is an arrow function (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace) in which match represent a matching element variable that you can treat. "gi" stands for global (search all occurences) and i for case insensitive – Big_Boulard Sep 12 '21 at 19:33
  • How `match` is getting it's value from heading . Instead I use any other word other than `match` code is working all right . So how does this `match` is getting value from heading . Also can you tell about how to count total number of cards . – Rana Sep 12 '21 at 20:34