Yupma
Yupma

Reputation: 2546

Text color change with search input but not work as expected

I have tried help from :
How to highlight text using javascript - Stackoverflow link
How do I get the starting and ending index of a highlighted piece of a string in Javascript? - Stackoverflow link
A one-line solution to highlighting search matches - Outside link

But reached upto a certain mark of achievement.

Now only first letters are highlighted . Also they get lowercase if I enter a lowercase letter in search and vice-versa
When the input is cleared , than the whole replace is shown including tag names

Here is what I reached upto :

function refree() {
  var reed = document.getElementById("search").value;
  var reed1 = reed.toLowerCase();
  var reader = document.getElementsByClassName("deviceNameCardHead")

  // for (let i = 0; i < reader.length; i++) {
  reader[0].innerHTML = reader[0].innerHTML.replace(new RegExp(reed1, 'gi'), `<span class="highlight">${reed}</span>`);
}
//}
.highlight {
  background: yellow;
}
<div id="devicesBtnData">
  <div class="searchDevice">
    <span class="searchDeviceBtn">Search Device</span>
    <input id="search" type="search" placeholder="Try it" oninput="refree()">
    <br>
  </div>

  <div class="deviceNameCard">
    <h3 class="deviceNameCardHead">Lenova Yoga laptop Pro</h3>
  </div>

</div>

Below answer solved most of the problems . But can there be a way such that :

Upvotes: 2

Views: 518

Answers (2)

Yupma
Yupma

Reputation: 2546

This can be the solution . But I don't know how match used here . It is my first time use of it . If anyone can tell about it in comments will be helpful

const reader = document.querySelector(".deviceNameCardHead");
const reader_text = reader.textContent;

function refree() {
  var reed = document.getElementById("search").value;
  var reed1 = reed.toLowerCase();

  // for (let i = 0; i < reader.length; i++) {
  reader.innerHTML = reader_text.replace(new RegExp(reed1, 'gi'), (match) => `<span class="highlight">${match}</span>`);
}
//}
.highlight {
  background: yellow;
}
<div id="devicesBtnData">
  <div class="searchDevice">
    <span class="searchDeviceBtn">Search Device</span>
    <input id="search" type="search" placeholder="Try it" oninput="refree()">
    <br>
  </div>

  <div class="deviceNameCard">
    <h3 class="deviceNameCardHead">Lenova Yoga laptop Pro</h3>
  </div>

</div>

Upvotes: 1

biberman
biberman

Reputation: 5767

Your regex isn't working if there is a span tag between the letters. Therefor you could replace reader[0].innerHTML with reader[0].textContent. This also solves the issue when the input is cleared.

By the way: if you use document.querySelector(...) you can omit the [0] in reader[0] because it only selects the first element with that selector.

Working example: (simple for demonstration)

function refree() {
  var reed = document.getElementById("search").value;
  var reed1 = reed.toLowerCase();
  var reader = document.querySelector(".deviceNameCardHead");

  reader.innerHTML = reader.textContent.replace(new RegExp(reed1, 'gi'), `<span class="highlight">${reed}</span>`);
}
.highlight {
  background: yellow;
}
<div id="devicesBtnData">
  <div class="searchDevice">
    <span class="searchDeviceBtn">Search Device</span>
    <input id="search" type="search" placeholder="Try it" oninput="refree()">
  </div>

  <div class="deviceNameCard">
    <h3 class="deviceNameCardHead">Lenova Yoga laptop Pro</h3>
  </div>
</div>


To solve the issue that it changes the case of the yellow letters you need a bit more code.

First you have to store the string from .deviceNameCardHead in a variable (for example reader_text), convert it to lower case for a case insensitive search and store that also in a variable (for example lower_text):

const reader_text = reader.textContent;
const lower_text = reader_text.toLowerCase();

Then you have to loop over all chars of reader_text to find all occurrences of the search string and store all index values in an array (for example index_array):

for(i = 0; i < lower_text.length; i++) {
  const reed_index = lower_text.indexOf(reed1, i);
    
  if(reed_index >= 0) {
    index_array.push(reed_index);
  }
}

Then you have to loop over the index_array and store all occurrences from the original string in an array (for example highlight_array) to obtain lower and upper case letters. To minimize an array to unique values you can use the Set() constructor and spread syntax [...].

index_array = [...new Set(index_array)];
index_array.forEach(function(val) {
  highlight_array.push(reader_text.substr(val, reed.length));
});

After that you have to loop over the highlight_array and replace all upper and lower case occurrences separately with span.highlight-wrapped values. To prevent the overwriting of reader_text use a separate variable (for example highlight_text):

let highlight_text = reader_text;

highlight_array = [...new Set(highlight_array)];
highlight_array.forEach(function(val) {
  highlight_text = highlight_text.replaceAll(val, `<span class="highlight">${val}</span>`);
});

And finally you have to replace the string from .deviceNameCardHead with highlight_text:

reader.innerHTML = highlight_text;

Working example:

const reader = document.querySelector(".deviceNameCardHead");
const reader_text = reader.textContent;
const lower_text = reader_text.toLowerCase();

function refree() {
  const reed = document.getElementById("search").value;
  const reed1 = reed.toLowerCase();
  let highlight_text = reader_text;
  let highlight_array = [];
  let index_array = [];
  
  for(i = 0; i < lower_text.length; i++) {
    const reed_index = lower_text.indexOf(reed1, i);
    
    if(reed_index >= 0) {
      index_array.push(reed_index);
    }
  }

  index_array = [...new Set(index_array)];
  index_array.forEach(function(val) {
    highlight_array.push(reader_text.substr(val, reed.length));
  });

  highlight_array = [...new Set(highlight_array)];
  highlight_array.forEach(function(val) {
    highlight_text = highlight_text.replaceAll(val, `<span class="highlight">${val}</span>`);
  });
  
  reader.innerHTML = highlight_text;
}
.highlight {
  background: yellow;
}
<div id="devicesBtnData">
  <div class="searchDevice">
    <span class="searchDeviceBtn">Search Device</span>
    <input id="search" type="search" placeholder="Try it" oninput="refree()">
  </div>

  <div class="deviceNameCard">
    <h3 class="deviceNameCardHead">Lenova Yoga press laptop Pro</h3>
  </div>
</div>

Upvotes: 0

Related Questions