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 class="lazyblock-faq-search">
<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 class="lazyblock-faq">
<div class="row">
<aside class="col-md-3">
<ul class="sticky-top">
<li class="active">
<a href="#chapter-1">Chapter 1</a>
</li>
<li class="">
<a href="#chapter-2">Chapter 2</a>
</li>
</ul>
</aside>
<div class="question-and-answer col-md-9">
<h2 id="chapter-1">Chapter 1</h2>
<div class="single-faq">
<h3>This is a question</h3>
<div class="icon-faq">
<span class="minus">+</span>
<span class="plus">–</span>
</div>
<div class="nodisplay collapse" style="display: none;">
<div class="lazyblock-content " id="content-extra-Z2cLmzB">
<div class="row">
<div class="col-md-12">
<p>This is the answer</p>
</div>
</div>
</div>
</div>
</div>
<div class="single-faq">
<h3>This is a question 2</h3>
<div class="icon-faq">
<span class="minus">+</span>
<span class="plus">–</span>
</div>
<div class="nodisplay collapse" style="display: none;">
<div class="lazyblock-content " id="content-extra-ZhBtAi">
<div class="row">
<div class="col-md-12">
<p>This is the answer 2</p>
</div>
</div>
</div>
</div>
</div>
<div class="single-faq">
<h3>Question 3 ?</h3>
<div class="icon-faq">
<span class="minus">+</span>
<span class="plus">–</span>
</div>
<div class="nodisplay collapse" style="display: none;">
<div class="lazyblock-content " id="content-extra-ZPm3XU">
<div class="row">
<div class="col-md-12">
<p>This is the answer 3</p>
</div>
</div>
</div>
</div>
</div>
<h2 id="chapter-2">Chapter 2</h2>
<div class="single-faq">
<h3>This is a question 4</h3>
<div class="icon-faq">
<span class="minus">+</span>
<span class="plus">–</span>
</div>
<div class="nodisplay collapse" style="display: none;">
<div class="lazyblock-content " id="content-extra-1sQXGa">
<div class="row">
<div class="col-md-12">
<p>This is just a test for question 4</p>
</div>
</div>
</div>
</div>
</div>
<div class="single-faq">
<h3>This is a question 5</h3>
<div class="icon-faq">
<span class="minus">+</span>
<span class="plus">–</span>
</div>
<div class="nodisplay collapse" style="display: none;">
<div class="lazyblock-content " id="content-extra-ZioRKT">
<div class="row">
<div class="col-md-12">
<p>This is just a test for question 5</p>
</div>
</div>
</div>
</div>
</div>
<div class="single-faq">
<h3>This is a quesition 6 and it has a weird layout</h3>
<div class="icon-faq">
<span class="minus">+</span>
<span class="plus">–</span>
</div>
<div class="nodisplay collapse" style="display: none;">
<div class="lazyblock-content " id="content-extra-2fxKyB">
<div class="row">
<div class="col-md-12">
<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:
-
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.
-
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.
-
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?