Home > Enterprise >  Search for a term from an input field and reset it if the is no value, problem with words with more
Search for a term from an input field and reset it if the is no value, problem with words with more

Time:04-11

I built an input field to search on my questions and answers page some keywords. The system that I built is more than that because it also opens and closes the div with the answer (both from the input and from different other HTML tags), but I'm focusing on the input field.

First my code and then my problem:

const searchfaq = $('#text-search');
const searchtarget = $(".nodisplay");
const htmltochange = searchtarget.map(function() {
  return $(this).children().find('p').html();
}).get();

function delay(callback, ms) {
  var timer = 0;
  return function() {
    var context = this,
      args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function() {
      callback.apply(context, args);
    }, ms || 0);
  };
}

searchfaq.keyup(delay(function(e) {
  let val = $(this).val().toLowerCase();
  searchtarget.hide();
  searchtarget.prev().children('.minus').removeClass('rotate');

  searchtarget.each(function(index) {
    let text = $(this).html().toLowerCase();
    let paragraph = $(this).children().find('p');
    let otherparagraph = searchtarget.children().find('p');

    if (text.indexOf(val) != -1) {
      $(this).show();
      $(this).prev().children('.minus').addClass('rotate');
      var re = new RegExp(val, 'gi');
      paragraph[0].innerHTML = htmltochange[index].replace(re, `<mark>$&</mark>`);
    }
    if (val.length === 0) {
      paragraph[0].innerHTML = htmltochange[index];
      $(this).hide();
      searchtarget.prev().children('.minus').removeClass('rotate');
    }
  });

}, 500));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div >
  <h1>Frequently Asked Questions</h1>
  <form _lpchecked="1">
    <input id="text-search" type="text" aria-label="search-for-answers" placeholder="Search for answers">
  </form>
</div>

<div >
  <div >
    <aside >
      <ul >
        <li >
          <a href="#chapter-1">Chapter 1</a>
        </li>
        <li >
          <a href="#chapter-2">Chapter 2</a>
        </li>
      </ul>
    </aside>
    <div >
      <h2 id="chapter-1">Chapter 1</h2>
      <div >
        <h3>This is a question</h3>
        <div >
          <span > </span>
          <span >–</span>
        </div>
        <div  style="display: none;">

          <div  id="content-extra-Z2cLmzB">
            <div >
              <div >
                <p>This is the answer</p>
              </div>
            </div>
          </div>

        </div>
      </div>
      <div >
        <h3>This is a question 2</h3>
        <div >
          <span > </span>
          <span >–</span>
        </div>
        <div  style="display: none;">

          <div  id="content-extra-ZhBtAi">
            <div >
              <div >
                <p>This is the answer 2</p>
              </div>
            </div>
          </div>

        </div>
      </div>
      <div >
        <h3>Question 3 ?</h3>
        <div >
          <span > </span>
          <span >–</span>
        </div>
        <div  style="display: none;">

          <div  id="content-extra-ZPm3XU">
            <div >
              <div >
                <p>This is the answer 3</p>
              </div>
            </div>
          </div>

        </div>
      </div>
      <h2 id="chapter-2">Chapter 2</h2>
      <div >
        <h3>This is a question 4</h3>
        <div >
          <span > </span>
          <span >–</span>
        </div>
        <div  style="display: none;">

          <div  id="content-extra-1sQXGa">
            <div >
              <div >
                <p>This is just a test for question 4</p>
              </div>
            </div>
          </div>

        </div>
      </div>
      <div >
        <h3>This is a question 5</h3>
        <div >
          <span > </span>
          <span >–</span>
        </div>
        <div  style="display: none;">

          <div  id="content-extra-ZioRKT">
            <div >
              <div >
                <p>This is just a test for question 5</p>
              </div>
            </div>
          </div>

        </div>
      </div>
      <div >
        <h3>This is a quesition 6 and it has a weird layout</h3>
        <div >
          <span > </span>
          <span >–</span>
        </div>
        <div  style="display: none;">

          <div  id="content-extra-2fxKyB">
            <div >
              <div >
                <p>This is just a test for question 6</p>
              </div>
            </div>
          </div>

        </div>
      </div>
    </div>
  </div>
</div>

The code works in this way. The user will insert a string in the input field and the word will be searched inside the div with the class 'no-display', precisely in its HTML (I had to specify it because, in the original code, the particular div will have HTML inside, not just text).

The code works with two caveats:

  1. I had to add a delay function because, for some reason, without it that would work only for the first two characters, then it won't be able to find any other word.

  2. Connect to problem 1, if you tried to insert another value (string) in the input field, it won't reset correctly in a sense that, it won't be able to find any different word. Let's take this example: I will insert the word test, then if I tried to delete a word from that, (string tes) it will still wrap it the word in the mark tag. But then, if I will add it again the character T at the end, it won't find the divs with the word test, the code will fail.

  3. Also, before resetting to the initial value (val.length === 0) I will see every word wrapped in a tag.

Is it a bug or am I missing something?

CodePudding user response:

For 1) and 2) (delay unrelated) your issue is that your comparison let text= uses the current html, not the original htmltochange.

After a search, the current html now has <mark> tags.

So if you search for " is " your html changes from This is the to This<mark> is </mark>the - when you then search for " is the" it doesn't match on <mark> is </mark>the.

Instead of .html(), use .text() to get the text without the markup, then it works fine (that part at least, not checked the rest, eg also change the original htmltochange). It also means you don't get false-positives, eg search for "div" in your original code, "div" appears in the html for every answer, so they're all shown.

  searchtarget.each(function(index) {
    let text = $(this).text().toLowerCase();
  1. resetting to the initial value (val.length === 0) will see every word wrapped in a tag

This is due to the order of ifs - your first if looks for a blank and highlights them, the second then hides them.

Reverse the order so that it checks for length===0 first, then only search if it's not 0.

Updated fiddle:

const searchfaq = $('#text-search');
const searchtarget = $(".nodisplay");
const htmltochange = searchtarget.map(function() {
  return $(this).children().find('p').text();
}).get();

function delay(callback, ms) {
  var timer = 0;
  return function() {
    var context = this,
      args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function() {
      callback.apply(context, args);
    }, ms || 0);
  };
}

searchfaq.keyup(delay(function(e) {
  let val = $(this).val().toLowerCase();
  //console.log(val)
  searchtarget.hide();
  searchtarget.prev().children('.minus').removeClass('rotate');

  searchtarget.each(function(index) {
    let text = $(this).text().toLowerCase();
    let paragraph = $(this).children().find('p');
    let otherparagraph = searchtarget.children().find('p');

    if (val.length === 0) {
      paragraph[0].innerHTML = htmltochange[index];
      $(this).hide();
      searchtarget.prev().children('.minus').removeClass('rotate');
    }
    else if (text.indexOf(val) != -1) {
      $(this).show();
      $(this).prev().children('.minus').addClass('rotate');
      var re = new RegExp(val, 'gi');
      paragraph[0].innerHTML = htmltochange[index].replace(re, `<mark>$&</mark>`);
    }
  });

}, 500));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div >
  <h1>Frequently Asked Questions</h1>
  <form _lpchecked="1">
    <input id="text-search" type="text" aria-label="search-for-answers" placeholder="Search for answers">
  </form>
</div>

<div >
  <div >
    <aside >
      <ul >
        <li >
          <a href="#chapter-1">Chapter 1</a>
        </li>
        <li >
          <a href="#chapter-2">Chapter 2</a>
        </li>
      </ul>
    </aside>
    <div >
      <h2 id="chapter-1">Chapter 1</h2>
      <div >
        <h3>This is a question</h3>
        <div >
          <span > </span>
          <span >–</span>
        </div>
        <div  style="display: none;">

          <div  id="content-extra-Z2cLmzB">
            <div >
              <div >
                <p>This is the answer</p>
              </div>
            </div>
          </div>

        </div>
      </div>
      <div >
        <h3>This is a question 2</h3>
        <div >
          <span > </span>
          <span >–</span>
        </div>
        <div  style="display: none;">

          <div  id="content-extra-ZhBtAi">
            <div >
              <div >
                <p>This is the answer 2</p>
              </div>
            </div>
          </div>

        </div>
      </div>
      <div >
        <h3>Question 3 ?</h3>
        <div >
          <span > </span>
          <span >–</span>
        </div>
        <div  style="display: none;">

          <div  id="content-extra-ZPm3XU">
            <div >
              <div >
                <p>This is the answer 3</p>
              </div>
            </div>
          </div>

        </div>
      </div>
      <h2 id="chapter-2">Chapter 2</h2>
      <div >
        <h3>This is a question 4</h3>
        <div >
          <span > </span>
          <span >–</span>
        </div>
        <div  style="display: none;">

          <div  id="content-extra-1sQXGa">
            <div >
              <div >
                <p>This is just a test for question 4</p>
              </div>
            </div>
          </div>

        </div>
      </div>
      <div >
        <h3>This is a question 5</h3>
        <div >
          <span > </span>
          <span >–</span>
        </div>
        <div  style="display: none;">

          <div  id="content-extra-ZioRKT">
            <div >
              <div >
                <p>This is just a test for question 5</p>
              </div>
            </div>
          </div>

        </div>
      </div>
      <div >
        <h3>This is a quesition 6 and it has a weird layout</h3>
        <div >
          <span > </span>
          <span >–</span>
        </div>
        <div  style="display: none;">

          <div  id="content-extra-2fxKyB">
            <div >
              <div >
                <p>This is just a test for question 6</p>
              </div>
            </div>
          </div>

        </div>
      </div>
    </div>
  </div>
</div>

  • Related