I've been trying to get my search filter to work but can't get it to work. I'm a beginner but trying my best to make it work. Anyone out there that can help :)
The html
<div class="notes_search">
<input type="search" id="search_input" onkeyup="searchFilter()" placeholder="Search...">
</div>
<ul class="notes_list">
</ul>
<p class="notes_empty-msg">Nothing to show.</p>
</section>
</div>
The Script down bellow.
function searchFilter() {
// Declare variables
var input, filter, ul, li, a, i;
input = document.getElementsById('search');
filter = input.value.toUpperCase();
ul = document.getElementsById('search')[0];
li = ul.getElementsByTagName("li");
for (i = 0; i < li.length; i++) {
a = li[i].getElementsByTagName("a")[0];
if (a.innerHTML.toUpperCase().indexOf(filter)===0) {
li[i].style.display = "";
} else {
li[i].style.display = "none";
}
}
}
There are a number of issues with your code.
First, it's getElementById not getElementsById, but you might find using querySelector and querySelectorAll easier to use as they match to CSS selectors (similar to jQuery).
Second, you don't have an element with a search id.
Third, your HTML contains no list items so it can't search for anything.
Here's a working version with annotations (using some more modern JS methods with which you might not be familiar but which can make the code more succinct). Note: it uses a class to make the items visible or not, and searches within the text content rather than just checking to see if it's at the start of the content which makes it a little more flexible.
function searchFilter() {
// You might find `querySelector` easier to use as it
// allows you to correspond elements with CSS selectors
const input = document.querySelector('#search');
const filter = input.value.toUpperCase();
const ul = document.querySelector('ul');
const lis = ul.getElementsByTagName("li");
for (i = 0; i < lis.length; i++) {
const item = lis[i];
const itemContent = item.textContent.toUpperCase();
// `textContent` might be more appropriate here
// You can use the newer string method `includes`
// to see if `filter` appears in the text content
if (filter.length && itemContent.includes(filter)) {
// Here I've used `classList` as the more modern
// method way of adding and removing classes
item.classList.add('visible');
} else {
item.classList.remove('visible');
}
}
}
li { display: none; }
.visible { display: block }
<div class="notes_search">
<input type="search" id="search" onkeyup="searchFilter()" placeholder="Search...">
</div>
<ul class="notes_list">
<li>Bob</li>
<li>Sue</li>
<li>Rita</li>
<li>Rita and Bob</li>
<li>John</li>
</ul>
<p class="notes_empty-msg">Nothing to show.</p>
</div>
Further reading
classList
String.includes
textContent
You have several things here that are incorrect:
It should be getElementById rather than getElementsById (not plural)
Your input element has the id of "search_input", but you're trying to find an element with the name "search". When looking for an element, it should be the exact name of id, and not a partial word containing it. So try input=document.getElementById('search_input');
Try using innerText rather than innerHtml: innerHtml returns in html format rather than plain text as I remember.
index.html
<div class="notes_search">
<input type="search" id="search_input" onkeyup="searchFilter()" placeholder="Search...">
</div>
<ul class="notes_list">
<li>hi</li>
<li>hi</li>
<li>bye</li>
</ul>
<p class="notes_empty-msg">Nothing to show.</p>
</section>
</div>
index.js
function searchFilter() {
// Declare variables
var input, filter, ul, li, a, i, text;
input = document.getElementById('search_input');
filter = input.value.toUpperCase();
ul = document.getElementsByClassName('notes_list')[0];
li = ul.getElementsByTagName("li");
for (i = 0; i < li.length; i++) {
a = li[i].getElementsByTagName("a")[0];
text = a.textContent || a.innerText;
if (a.innerHTML.toUpperCase().indexOf(filter)===0) {
li[i].style.display = "";
} else {
li[i].style.display = "none";
}
}
}
I also added some li and a tag items to your html, since you didn't have them and it can't find tags that isn't on the html.
I am not fully sure what you are trying to achieve but would a simple html datalist work for your problem:
<input list="your-choices" id="search_input" placeholder="Search...">
<datalist id="your-choices">
<option value="car">
<option value="tree">
<option value="street">
<option value="sky">
<option value="whatever">
</datalist>
You Can search by Jquery
var searchRequest = null;
$(function () {
var minlength = 3;
$("#sample_search").keyup(function () {
var that = this,
value = $(this).val();
if (value.length >= minlength ) {
if (searchRequest != null)
searchRequest.abort();
searchRequest = $.ajax({
type: "GET",
url: "sample.php",
data: {
'search_keyword' : value
},
dataType: "text",
success: function(msg){
//we need to check if the value is the same
if (value==$(that).val()) {
//Receiving the result of search here
}
}
});
}
});
});
Related
I created an HTML table with a lot of information about a country. Now I want the user to be able to search in this table for a piece of information like the Area.
function selectRow() {
var input, filter, table, trs, td;
input = document.getElementById("search");
filter = input.value.toUpperCase();
table = document.getElementById("dataRows");
trs = table.getElementsByTagName("tr");
for (let index = 0; index < trs.length; index++) {
td = trs[index].getElementsByTagName("td")[0];
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
trs[index].display = "";
} else {
trs[index].display = "none";
}
}
}
<input type="text" id="search" onkeyup="selectRow()" placeholder="Search.." />
<table id="dataRows">
<tr>
<th>Attributes</th>
<th>Value</th>
</tr>
<tr>
<td>Name</td>
<td>Australia</td>
</tr>
<tr>
<td>Area</td>
<td>7,741,220.00</td>
</tr>
<tr>
<td>Population</td>
<td>25,466,459</td>
</tr>
</table>
But when I try to use it I get the error: "Uncaught TypeError: Cannot read property 'innerHTML' of undefined"
I can't figure out why the td is undefined.
The most helpful thing to demonstrate first, I think, is a method that will let you diagnose this yourself in future. This sort of difficulty will occur all the time, so here is one method to help you generally problem solve these types of issues.
You know that <td> is not the value you expect, so check your expectation by outputting the values that you use to acquire <td>. You can do that by adding these console.log lines at the top of your loop:
for (let index = 0; index < trs.length; index++) {
console.log("trs[index]",trs[index]);
console.log("trs[index].getElementsByTagName(td)", trs[index].getElementsByTagName("td"));
With that, you should see that the first <tr> has <th> elements, not <td>! These surprises happen all the time, it's great to learn tricks to check your assumptions the quickest way you can.
Here's a very simple solution, the first and last line of this block are the same in your code:
for (let index = 0; index < trs.length; index++) {
var tds = trs[index].getElementsByTagName("td");
if(tds.length == 0) {
continue;
}
td = tds[0];
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
Looks like you've just started working through building this, I hope this helps!
<script>
function myFunction() {
// Declare variables
var input, filter, ul, li, a, i, txtValue;
input = document.getElementById('myInput');
filter = input.value.toUpperCase();
ul = document.getElementById("myUL");
li = ul.getElementsByTagName('li');
// Loop through all list items, and hide those who don't match the search query
for (i = 0; i < li.length; i++) {
a = li[i].getElementsByTagName("a")[0];
txtValue = a.textContent || a.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
li[i].style.display = "";
} else {
li[i].style.display = "none";
}
}
}
</script>
use ur code like this to get best result and without any error
edit
I think the tricky part of this is actually the accepting of user input intelligently. Therefore, I'd say the best thing to do is to pass off your searching to an autocomplete-type plugin. Once the page is ready, you pass the focus to an input text box, and then let the plugin do its magic as you search...
For example, you could use the quicksearch plugin.
Then given a table of data and an input like this:
<input id="searcher" type="text" name="searcher">
You could have a ready function that looks like this:
$('#searcher').quicksearch('table tbody tr', {
'delay': 100,
'bind': 'keyup keydown',
'show': function() {
if ($('#searcher').val() === '') {
return;
}
$(this).addClass('show');
},
'onAfter': function() {
if ($('#searcher').val() === '') {
return;
}
if ($('.show:first').length > 0){
$('html,body').scrollTop($('.show:first').offset().top);
}
},
'hide': function() {
$(this).removeClass('show');
},
'prepareQuery': function(val) {
return new RegExp(val, "i");
},
'testQuery': function(query, txt, _row) {
return query.test(txt);
}
});
$('#searcher').focus();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Try it out here: http://jsfiddle.net/ZLhAd/369/
I'm trying to make a read out website, with a long text that we can only read out, without any possible scrolling. But I'm not really good with pure JS and I'm a little bit lost. I tried speech recognition and in a second time to make a filter/search list.
In an other side, I'm taking each words of a <p> to separate them in <spans>, because I suppose I have to make something like "When you
hear <span>1</span>, you wait to hear <span>2</span>" and so on...
But for the moment, I'm making a list and not span, like that :
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Say something..." title="Type in a name">
<ul id="myUL">
<li>Hello world</li>
<li>Bye world</li>
<li>See you world</li>
</ul>
And JS :
function myFunction() {
var input, filter, ul, li, a, i;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
ul = document.getElementById("myUL");
li = ul.getElementsByTagName("li");
for (i = 0; i < li.length; i++) {
a = li[i].getElementsByTagName("a")[0];
if (a.innerHTML.toUpperCase().indexOf(filter) > -1) {
li[i].style.display = "";
} else {
li[i].style.display = "none";
}
}
}
Then, in a second time I tried to merge it with a speechRecognition input, without success :
<form>
<input type="button" id="btn" value="start" />
</form>
<div id="interimResult"></div>
<div id="finalResult">Let speak</div>
I did a fiddle where I separate the two function now because I didn't find anything...
But, Am I going in the good way... I have to manage long text and <li> are not good, when I'll make it with <span> or anything else, will it be the same method ?
You add a call to myFunction inside recognition.onresult, you also modify myFunction to accept recognized text as an argument, it will do the job:
function myFunction(filter) { // HERE WE TAKE FILTER AS AN ARGUMENT
var ul, li, a, i;
ul = document.getElementById("myUL");
li = ul.getElementsByTagName("li");
for (i = 0; i < li.length; i++) {
a = li[i].getElementsByTagName("a")[0];
if (a.innerHTML.toUpperCase().indexOf(filter) > -1) {
li[i].style.display = "";
} else {
li[i].style.display = "none";
}
}
}
recognition.onresult = function(event) {
var interimTranscript = "";
for (var i = event.resultIndex; i < event.results.length; i++) {
var _transcript = event.results[i][0].transcript;
if (event.results[i].isFinal) {
finalTranscript = StringUtils.capitalize(_transcript);
myFunction(finalTranscript); // <-- HERE IT FILTERS
// USING SPEECH RECOGNITION RESULT
}
It is better to give your function myFunction more meaningful name though, for example filterView is much better name.
I am trying to use this example by w3schools to add a search bar. I can't get it to work, I have changed it to match my elements but with no success. I have to have my js separate from the HTML document so no <script>
My issue is that It does not work, and I do not know how to debug it.
Here is my js file:
//search bar
function myFunction() {
// Declare variables
var input, filter, ul, div, li, a, span, i;
input = document.getElementById('myInput');
filter = input.value.toUpperCase();
ul = document.getElementById("container");
span = ul.getElementsByTagName('span');
// Loop through all list items, and hide those who don't match the search query
for (i = 0; i < li.length; i++) {
a = span[i].getElementsByTagName("a")[0];
if (a.innerHTML.toUpperCase().indexOf(filter) > -1) {
span[i].style.display = "";
} else {
span[i].style.display = "none";
}
}
}
document.getElementById('myInput').addEventListener('keyup', myFunction);
And my HTML file
<div class="container">
<input type="text" id="myInput" placeholder="Search for names..">
<div id="container">
<span>Nico Nico Nii!!</span>
<span>Childish Gambino - Redbone</span>
<span>America F*ck Yeah!</span>
</div>
</div>
Firstly, you have a lot of unnecessary variables. You only need two, one to get the values of the list and the other to get value of filter. If there are more than one element, use class instead. See the working code below:
//search bar
function myFunction() {
var input, filter;
input = document.getElementsByClassName('myLinks');
filter = document.getElementById('myInput').value.toUpperCase();
// Loop through all list items, and hide those who don't match the search query
for (i = 0; i < input.length; i++) {
var currentElem = input[i];
var currentElemChild = input[i].children[0]
if (currentElemChild.innerHTML.toUpperCase().indexOf(filter) > -1) {
currentElem.style.display = "";
} else {
currentElem.style.display = "none";
}
}
}
document.getElementById('myInput').addEventListener('keyup', myFunction);
<div>
<input type="text" id="myInput" placeholder="Search for names..">
<ul id="container">
<li class="myLinks">Nico Nico Nii!!</li>
<li class="myLinks">Childish Gambino - Redbone</li>
<li class="myLinks">America F*ck Yeah!</li>
</ul>
</div>
I am working on some line in JS to do a live search. I have been trying to modify this https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_filter_list
to do what I am looking for, how ever I cant seem to understand what I am doing wrong. any pointers or corrections are greatly appreciated.
JS it should hide any twit that does not contain the search
var navbarSearchbutton = document.getElementById('navbar-search-button')[0];
navbarSearchbutton.addEventListener('onkeyup', function() {
searchFunction();
});
function searchFunction() {
var input, filter, ul, li, a, i, foo;
foo = document.getElementsByClassName("twit");
input = document.getElementById("navbar-search-input");
filter = input.value.toUpperCase();
li = document.getElementsByClassName("twit-text");
for (i = 0; i < li.length; i++) {
a = li[i].getElementsByTagName("P")[0];
if (a.innerHTML.toUpperCase().indexOf(filter) > -1) {
li[i].style.display = "";
} else {
foo[i].style.display = "none";
}
}
}
HTML for the search box and what I am searching.
<li class="navitem navbar-search">
<input type="text" id="navbar-search-input" placeholder="Search...">
<button type="button" id="navbar-search-button"><i class="fa fa-search"></i></button>
</li>
</ul>
</nav>
</header>
<main class="twit-container">
<article class="twit">
<div class="twit-icon">
<i class="fa fa-bullhorn"></i>
</div>
<div class="twit-content">
<p class="twit-text">
A body in motion must remain in motion unless acted upon by an outside force.
</p>
<p class="twit-attribution">
NewtonRulez
</p>
</div>
First, you are getting ('navbar-search-button by id. So, it will not return an id.
Second, the logic of searching by class name will not work. Below is an updated search function. I kept the same logic you are following to search for items by class names. You will need to to set the class name as twit-attribution for any new entry.
function searchFunction() {
var input, filter, ul, li, a, i, foo;
foo = document.getElementsByClassName("twit");
input = document.getElementById("navbar-search-input");
filter = input.value.toUpperCase();
li = document.getElementsByClassName("twit-attribution");
for (i = 0; i < li.length; i++) {
a = li[i];
if (a.innerHTML.toUpperCase().indexOf(filter) > -1) {
a.style.display = "";
} else {
a.style.display = "none";
}
}
}
I would like to search by any term (name, user, from, price), and display the div into top and hide the ones who doesn't have the typed value.
Here's the jsfiddle: http://jsfiddle.net/Sc9ys/10/
I would like to have the same result as the jquery mobile table filter http://demos.jquerymobile.com/1.4.0/filterable/
Where you can search for any term.
I know that for search for any term I should use $(list).find("li *:)... but I can't figure out how to display the items properly. If you test my jsfiddle it doesn't work very well.
Edit: As asked by the user below, here's some more info.
<ul id='list'>
<li>
<div class='row'>
<div class='middle'>
<ul>
<li><h3>Stackoverflow</h3></li>
<li><span>User</span></li>
<li><span>London</span></li>
</ul>
</div>
<div style='clear: both'></div>
</div>
</li>
</ul>
$("#search").change( function () {
$(list).find("li *:not(:Contains(" + filter + "))").parent().hide();
});
DEMO
The idea is in
$("#ul_container").find("li").filter(function () {//your comparing logic here });
Here, try this out. Honesty I couldn't read thru your code, so I made this example. I added the sub items (spans that contain data to be searched) in an array datalist by their class name.
Generic Search Function.
HTML
<input type="text" id="search" />
<ul id="ul_container">
<li class="listItem">
<span class="car">Honda</span>
<span class="country">Japan</span>
</li>
<li class="listItem">
<span class="car">BMW</span>
<span class="country">Germany</span>
</li>
</ul>
Script:
//Capture user input
$("#search").on("keyup change", function () {
var str = $.trim($(this).val());
if (str) {
search(str);
} else {
// if no input, then show all
$(".listItem").show();
}
});
//the search part.
var datalist = ["car", "country"];
function search(toFind) {
//select all li and loop thru them one by one
$("#ul_container").find("li").filter(function () {
var $li = $(this);//hold current li in a variable
//loop thru all sub spans by their class and check if the toFind keyword is there
// you modify this step, i use it to specify which sub span to be searched. Sometimes I don't want all field to be searched, only the ones I select.
for (var i = 0; i < datalist.length; i++) {
//hold the span in a var called $item
var $item = $li.children("." + datalist[i]);
var content_str = $item.html();//get the actual string
//the comparing code
if (content_str.toLowerCase().indexOf(toFind.toLowerCase()) >= 0) {
$li.show();
break;
} else {
$li.hide();
}
}
});
}
Solved guys. Thank you all.
You can see the following example working at: http://jsfiddle.net/Sc9ys/29/
$('#search').on('keyup change', function(){
var str = $.trim($(this).val());
if (str) {
search(str, $("#list"));
} else {
$("#list").find('li').show();
/* The <li> are display: none, to show them again if the input type is clear,
we must find those <li> and show them. Showing only the #list isn't enough. */
}
});
function search(toFind, list){
$(list).find('li').filter(function() {
$li = $(this);
$li.find(".middle :contains(" + toFind +")").parent().parent().slideDown();
$li.find(".middle").not(":contains(" + toFind + ")").parent().parent().slideUp();
});
}
/* Function to search with the input lowercase */
$.expr[":"].contains = $.expr.createPseudo(function(arg) {
return function( elem ) {
return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
};
});
Edit: Made some adjustments according to the help of user #Joraid.