Reputation: 15307
I am doing a search and highlight functionality. when the user types in first time, it all works. but next keyup
(adding other letter in text box) the function not working.
I strongly beleave that, when i am doing the 'replaceWith' - which is adding the ""
double quotes on the text. so the regexp
fails...
how to handle this issue?
UPDATE
I updated my code. it's somewhat works. but the problem is it's only selects one
letter in case there is a word match.
var input = $('#keyWord');
var origional = $('.container');
var content = $('.container *');
var highlight = function (str, className) {
var regex = new RegExp(str, "gi");
if(origional.find('.searchHighlight').length) {
origional.find('.searchHighlight').replaceWith(function() {
return $(this).contents();
});
}
content.each(function () {
$(this).contents().filter(function() {
return this.nodeType == 3 && regex.test(this.nodeValue);
}).replaceWith(function() {
return (this.nodeValue || "").replace(regex, function(match) {
return "<span class=\"" + className + "\">" + match + "</span>";
});
});
});
};
input.on('input', function(event) {
event.preventDefault();
var searchWrod = event.target.value;
if(!searchWrod) {
origional.find('.searchHighlight').replaceWith(function() {
return $(this).contents();
});
return;
}
highlight(searchWrod, 'searchHighlight');
});
.searchHighlight{
border:1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolor error sint eaque ratione quasi a, ullam tenetur sed voluptas est nulla adipisci reiciendis libero nesciunt obcaecati! Repellat labore voluptatum numquam.</div>
<div>Voluptates ipsum a at reiciendis iure nemo, inventore eligendi ut, ex necessitatibus similique dolore quae qui voluptatem, amet iste dolorum reprehenderit cum modi quibusdam unde asperiores. Magni laboriosam porro, repellat.</div>
<div>Ducimus esse alias odit, ipsa iusto similique unde. Accusantium laudantium temporibus est nobis quaerat impedit facere aut eum quas, cupiditate, dignissimos reprehenderit quia deserunt similique illum unde dolor dolorem harum.</div>
<div>Culpa rerum optio labore vero reprehenderit nulla laborum ducimus ipsum, animi fugiat, at, ipsa maiores. Consectetur doloremque, quia praesentium excepturi tempore, quisquam delectus dolorum aliquid reprehenderit cumque earum. Distinctio, voluptatibus?</div>
<div>Quis quos, iste placeat rerum facere dolorum deleniti natus architecto dolores possimus recusandae, alias esse sapiente sequi. Recusandae animi itaque iste, quas, nisi at, deserunt expedita, praesentium veniam numquam adipisci.</div>
<div>Ducimus itaque corporis perspiciatis consequatur ut saepe unde non voluptates, debitis, eum similique nobis fugiat sunt illum ipsa accusamus asperiores animi? Amet quas animi odit nam accusantium excepturi cum, error.</div>
<div>Nam mollitia esse eligendi saepe, ipsa soluta, repellat ullam perspiciatis nisi nemo quos quas alias molestiae nulla, obcaecati deleniti asperiores cumque illo dolore! Minus dolorem, voluptate reiciendis, distinctio consequuntur esse?</div>
<div>Iure blanditiis quis cumque quo rem expedita fugit soluta ullam? Possimus quia ratione alias amet vitae, a voluptatem, repellendus dolor neque? Eos vitae laborum, architecto mollitia temporibus eius maiores nobis?</div>
<div>Assumenda quod soluta odio harum unde blanditiis ab odit sapiente ducimus quidem recusandae molestias porro placeat corrupti, obcaecati nostrum quasi ex repudiandae earum omnis ipsum architecto neque quas rerum. Maxime.</div>
<div>Amet expedita magnam at alias praesentium, doloremque tenetur facilis dolor itaque necessitatibus eum ducimus repudiandae, nobis corrupti sequi eveniet voluptatum. Enim, id nostrum iste animi cupiditate totam. Voluptas, aliquid, dolorem.</div>
<div class="row">
<input type="text" name="keyword" id="keyWord">
</div>
</div>
How to come up with this issue?
Upvotes: 0
Views: 559
Reputation: 4659
I wrote the answer with your original code, but changed CSS border
to outline
so the text doesn't jump around upon typing.
Your problem is that when you do the replacement for the highlighting of the first letter, the textNode gets "cut up" into pieces. Even deleting the <span>
you put around it, doesn't concatenate the textNodes back into 1 big textNode.
So searching for P
means the content PageMaker
gets cut up into <span>P</span>
and ageMaker
. Then when you search for Pa
, you delete the <span>
but the code is still searching in 2 separate nodes P
and ageMaker
. Neither of them contain Pa
, so nothing gets highlighted.
Simply doing $("#test").html($("#test").html());
solves this issue.
Besides that I changed the order in the keyup
so the highlight gets deleted when there's an empty search-query. As well I added a replace to the input-string to escape any characters that are interpreted as special characters in a regex. In your original code, search for y.
would be interpreted as a regex meaning "Search for a y followed by any character except line-break." because that's the meaning of a .
in regexes. Escaping these characters fixes this.
var highLighter = function (str) {
var regex = new RegExp(str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), "gi");
$('#test *').each(function () {
$(this).contents().filter(function() {
return this.nodeType == 3;
}).replaceWith(function() {
return (this.nodeValue || "").replace(regex, function(match) {
return "<span class='highlight'>" + match + "</span>";
});
});
});
}
$('#keyWord').on('input', function (e) {
var text = e.target.value;
$(".highlight").replaceWith(function() { return $(this).text(); });
$("#test").html($("#test").html()); // concatinates adjacent text-nodes back to a single text-node
if(!text) return;
highLighter(text);
});
.highlight{
outline:1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="parent">
<div id="test">
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
</div>
</div>
<input type="text" id="keyWord" />
Upvotes: 2
Reputation: 4006
One way would be to loop through children's text of main text holder in this case #test
and then replace the children's html with searched text wrapped in .highlight
$('#keyWord').on('input', function (e) {
var text = $(this).val();
// escaping string for use in regex
text = text.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
var re = new RegExp(text, 'gi');
$('#test').children().each(function () {
// if no text input clear out previous .highlight spans
if(!text){
$(this).html($(this).text());
return;
}
// if match for regex insert .highlight class
$(this).html($(this).text().replace(re, function(match){
return '<span class="highlight">'+ match +'</span>';
}));
});
});
.highlight{
border:1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="parent">
<div id="test">
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
</div>
</div>
<input type="text" id="keyWord" />
Upvotes: 1