2

I am trying to make a pure JavaScript search box. I want it to search very loosely, i.e. it shouldn't be case sensitive, it shouldn't take spaces into account, etc.

I came upon this codepen, which has what I'm looking for, but it's written using JQuery. I'm trying to convert it to JavaScript only, but I'm having trouble doing it.

My question isn't on the animation, it's on the bare minimum search code. So basically here's the only part I need help with:

$.extend($.expr[':'], { 'containsi': function(elem, i, match, array) { return (elem.textContent || elem.innerText || '').toLowerCase() .indexOf((match[3] || "").toLowerCase()) >= 0; } }); var searchSplit = searchTerm.replace(/ /g, "'):containsi('") $("#list li").not(":containsi('" + searchSplit + "')").each(function(e) { $(this).addClass('hidden'); }); $("#list li:containsi('" + searchSplit + "')").each(function(e) { $(this).removeClass('hidden'); }); 

I got the JavaScript equivalent of JQuery's extend which is in the JSFiddle bellow.

JSFiddle

$(document).ready(function() { // My JavaScript code var input = document.getElementById('search-text'); input.addEventListener("keyup", function() { var searchTerm = input.value, listItem = document.getElementsByClassName('searchArray'); // JavaScript equivalent of jQuery's extend method function extend(a, b) { for (var key in b) if (b.hasOwnProperty(key)) a[key] = b[key]; return a; } }); // Bare minimum code from http://codepen.io/robooneus/pen/ivdFH //we want this function to fire whenever the user types in the search-box $("#search-text").keyup(function() { //first we create a variable for the value from the search-box var searchTerm = $("#search-text").val(); //then a variable for the list-items (to keep things clean) var listItem = $('#list').children('li'); //extends the default :contains functionality to be case insensitive //if you want case sensitive search, just remove this next chunk $.extend($.expr[':'], { 'containsi': function(elem, i, match, array) { return (elem.textContent || elem.innerText || '').toLowerCase() .indexOf((match[3] || "").toLowerCase()) >= 0; } }); //end of case insensitive chunk //this part is optional //here we are replacing the spaces with another :contains //what this does is to make the search less exact by searching all words and not full strings var searchSplit = searchTerm.replace(/ /g, "'):containsi('") //here is the meat. We are searching the list based on the search terms $("#list li").not(":containsi('" + searchSplit + "')").each(function(e) { //add a "hidden" class that will remove the item from the list $(this).addClass('hidden'); }); //this does the opposite -- brings items back into view $("#list li:containsi('" + searchSplit + "')").each(function(e) { //remove the hidden class (reintroduce the item to the list) $(this).removeClass('hidden'); }); }); });
.hidden { display: none; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <input type="text" id="search-text" placeholder="search"> <ul id="list"> <li class="searchArray">Apple pie</li> <li class="searchArray">Pumpkin pie</li> <li class="searchArray">Banana-creme pie</li> <li class="searchArray">Peach-blackberry cobbler</li> <li class="searchArray">Chocolate-strawberry torte</li> <li class="searchArray">Chocolate-zucchini cake</li> <li class="searchArray">Anything involving chocolate and mint</li> <li class="searchArray">Red-velvet cake</li> <li class="searchArray">Anything involving fruits that aren't cherries</li> </ul>

2
  • "but it's written using JQuery. I'm trying to convert it to JavaScript only, but I'm having trouble doing it." Why are you using jQuery at jsfiddle ? Is requirement to not use jQuery ? Commented Feb 21, 2016 at 6:59
  • I want the code to function so you can see how it works. If you noticed, I have 2 keyup events. 1 is JavaScript, the other is JQuery. I believe I noted it down in the comments of the JSFiddle Commented Feb 21, 2016 at 7:01

1 Answer 1

1

You can use a version of typeahead.js substringMatcher function

var substringMatcher = function(strs, q, cb) { return (function(q, cb, name) { var matches, substrRegex; // an array that will be populated with substring matches matches = []; // regex used to determine if a string contains the substring `q` substrRegex = new RegExp(q, 'i'); // iterate through the pool of strings and for any string that // contains the substring `q`, add it to the `matches` array strs.forEach(function(str, i) { if (substrRegex.test(str)) { // the typeahead jQuery plugin expects suggestions to a // JavaScript object, refer to typeahead docs for more info matches.push(name(str)); } }); cb(matches); }(q, cb, function(res) { return res })); }; var elems = document.getElementsByClassName('searchArray'); // My JavaScript code var listItem = Array.prototype.slice.call(elems); var list = listItem.map(function(el) { el.className = el.className + " " + "hidden"; return el.textContent; }) var input = document.getElementById('search-text'); input.addEventListener("keyup", function() { var searchTerm = this.value; if (searchTerm.length === 0) { listItem.forEach(function(el, i) { el.className = el.className + " " + "hidden" }); return false } substringMatcher(list, searchTerm, function(results) { results.forEach(function(value, index) { if (list.indexOf(value) > -1) { elems[list.indexOf(value)].className = elems[list.indexOf(value)] .className.replace("hidden", ""); } else { listItem.forEach(function(el, i) { if (i !== list.indexOf(value)) { el.className = el.className + " " + "hidden"; } }) } }) }) });
.hidden { display: none; }
<input type="text" id="search-text" placeholder="search"> <ul id="list"> <li class="searchArray">Apple pie</li> <li class="searchArray">Pumpkin pie</li> <li class="searchArray">Banana-creme pie</li> <li class="searchArray">Peach-blackberry cobbler</li> <li class="searchArray">Chocolate-strawberry torte</li> <li class="searchArray">Chocolate-zucchini cake</li> <li class="searchArray">Anything involving chocolate and mint</li> <li class="searchArray">Red-velvet cake</li> <li class="searchArray">Anything involving fruits that aren't cherries</li> </ul>

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the answer! I tried your example, but the search didn't work as expected. If nothing was in the search box, nothing shows up. If I enter anything in it, all the things show up
@Horay Well, did not refine the search algorithm due to this portion of original post: "I want it to search very loosely, i.e. it shouldn't be case sensitive, it shouldn't take spaces into account, etc." . Not certain if search was for first letter or any part of items in array? You can remove the part where no results shown be removing if that checks for search term value .length . You should be able to modify both the search criteria and results shown from template

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.