Insensitive search when typing in INPUT

Asked

Viewed 83 times

2

I have the Javascript search engine below. The problem is that when I write the word "Tomato" he seeks the word "Tomatoes". It’s probably a sensitivity problem or it’s just picking up part of the typed word. It would be possible to fix this using Javascript or jQuery only?

$("#box").on('keyup', function() {
   var matcher = new RegExp($(this).val(), 'gi');
	$('.connect-cat').show().not(function() {
	   return matcher.test($(this).find('.name, .category').text())
    }).hide();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input placeholder='Search' id='box' type='text' />
<div style='clear:both;'></div>
			
<div class='connect-cat'>
	<span class='name'>tomatoes</span>
</div>
			
<div class='connect-cat'>
	<span class='name'>tomato</span>
</div>
   
<div class='connect-cat'>
	<span class='name'>apple</span>
</div>

2 answers

1


The return you expect from the function within the .not() must be a element, one selector or a array (documentation of .not()). As it stands, the return is being a boolean true or false, which has no effect on the method.

Change the return for a ternary that will return the element itself (if the condition is true) or null (if it’s false). That is, by returning the element itself, it will not suffer the .hide() posterior.

return matcher.test($(this).find('.name, category').text()) ? $(this) : null;

Regarding the search, there are two ways to solve this:

1. Using .test():

Remove the flag g (global), because the behavior of this flag with .test and .exec is different from .match (document to get a sense of this).

$("#box").on('keyup', function(){
   var matcher = new RegExp($(this).val(), 'i');
   $('.connect-cat').show().not(function(){
       return matcher.test($(this).find('.name, category').text()) ? $(this) : null;
   }).hide();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input placeholder='Search' id='box' type='text' />
<div style='clear:both;'></div>
<div class='connect-cat'>
   <span class='name'>tomatoes</span>
</div>
   
<div class='connect-cat'>
   <span class='name'>tomato</span>
</div>

<div class='connect-cat'>
   <span class='name'>tomatos</span>
</div>

<div class='connect-cat'>
   <span class='name'>apple</span>
</div>

2. Using .match():

$("#box").on('keyup', function(){
   var matcher = new RegExp($(this).val(), 'gi');
   $('.connect-cat').show().not(function(){
      return $(this).find('.name, category').text().match(matcher) ? $(this) : null;
   }).hide();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input placeholder='Search' id='box' type='text' />
<div style='clear:both;'></div>
<div class='connect-cat'>
   <span class='name'>tomatoes</span>
</div>
   
<div class='connect-cat'>
   <span class='name'>tomato</span>
</div>

<div class='connect-cat'>
   <span class='name'>tomatos</span>
</div>

<div class='connect-cat'>
   <span class='name'>apple</span>
</div>

Edit

Just to reinforce and contrary to what the other answer states, the flag g IT DOES HAVE TO DO WITH with the form that the .test() works, as per can be seen in this documentation, that I report again. It seems to me that the our friend of the other answer did not read, or read and did not understand.

Also as per this answer in the Soen:

When you use a global flag on a JS Regexp the "test" and "exec" each methods Halt at the first match but Keep a Pointer to Where they stopped Searching in the string. That Pointer can be inspected on the lastIndex Property. When you call "test" or "exec" Again it Begins Searching for a match Starting at the lastIndex.

So, when you test a Regexp on a string that Matches the entire string the lastIndex is set to the end of the string. The next time you test it Starts at the end of the string, Returns false, and sets lastIndex back to zero.

Free translation:

When you use the global flag (g) in a Javascript regex, both "test" and "exec" methods stop at first match and maintain this position in the string search. This position can be checked in the lastIndex property. When you call the "test" or "exec" again, the search will start from the last verified position (cyto: This explains the malfunction that was occurring).

So when you test a Regexp on a string that will match the whole string, lastIndex will be at the end of the string. The next time you test, will start at the end of the string, returning false, and redefining lastIndex back to zero.

0

The way you used regex

new RegExp($(this).val(), 'gi');

For sure the use of regex so will give problem always, because you have no control over value val()

Even the problem of "Tomato" finding "Tomatoes" is because there are no "delimiters" ^ and $ at the beginning and end of the regex, and for the record, the problem has nothing to do with the modifier g.

Besides, it’s a lot of complexity without need, just use .toLowerCase in both compared values, example:

$("#box").on('keyup', function() {
    var matcher = $(this).val().toLowerCase();

	$('.connect-cat').show().not(function() {
	   return matcher == $(this).find('.name, .category').text().toLowerCase()
    }).hide();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input placeholder='Search' id='box' type='text' />
<div style='clear:both;'></div>
			
<div class='connect-cat'>
	<span class='name'>tomatoes</span>
</div>
			
<div class='connect-cat'>
	<span class='name'>tomato</span>
</div>
   
<div class='connect-cat'>
	<span class='name'>apple</span>
</div>


If the intention is to search for words that start with what was typed you can use .indexOf() == 0

var matcher = $(this).val().toLowerCase();

$('.connect-cat').show().not(function() {
   return matcher.indexOf( $(this).find('.name, .category').text().toLowerCase() ) == 0
}).hide();

If the intention is to search for words that contain part of what was typed you can use .indexOf() != -1

var matcher = $(this).val().toLowerCase();

$('.connect-cat').show().not(function() {
   return matcher.indexOf( $(this).find('.name, .category').text().toLowerCase() ) != -1
}).hide();
  • @dvd so you usually think about voting for people and the empathy you have for them and not the content and quality of the content? Interesting to know.

  • @dvd where exactly not working, I would be very grateful if you explained where failed, is that difference in Firefox, or failed in Internet explorer?

  • @dvd What I answered was what I understood of what the AP wanted (which actually is not very clear), I understood that should not appear Omatoes when typing Omato, so it seems to me that the typed word would have to be exact, but if not this I will accept your criticism yes, because if the understanding was wrong on my part it is very fair and praiseworthy to criticize and receive criticism ;)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.