Javascript live search not responding? - javascript

Trying to create a live search using javascript and it seems as if the script is not responding. I have the script within a .js file and I have added it at the end of the page.
The functionality I want is when the user types into #PokemonSearch it will hid irrelevant pokemon-selector-item divs
What happens when I type into #PokemonSearch with the following code? Absolutely nothing.
$(document).ready(function(){
$("#PokemonSearch").keyup(function(){
// Retrieve the input field text and reset the count to zero
var filter = $(this).val(), count = 0;
// Loop through the comment list
$(".pokemon-selector-item").each(function(){
// If the list item does not contain the text phrase fade it out
if ($(this).attr(".pokemon-name").text().search(new RegExp(filter, "i")) < 0) {
$(this).fadeOut();
// Show the list item if the phrase matches and increase the count by 1
} else {
$(this).show();
count++;
}
});
});
});
HTML Selector item example:
<div class="pokemon-selector-item">
<img class="pokemon-image" src="~/assets/images/pokemon/pokemon-50x50/charmander.png" />
<div class="pokemon-selector-info">
<span class="pokemon-name">Charmander</span>
<span class="pokemon-type">Fire Pokemon</span>
</div>
</div>

You have a typo. .attr(".pokemon-name") on line 11 should be .find(".pokemon-name")

Related

"[i - 1]" is Not Getting the Last Element of a List (JavaScript)

The Problem:
Hey everyone. I'm trying to create a simple function that identifies the next and previous elements of a current item within the ".length" of elements in a div, and then changes the ID of those two elements. Everything is working except for the part where it tries to identify the previous element at the beginning and the next element at the end.
What I've Tried:
It used to be that it would identify those items by using ".nextElementSibling" and ".previousElementSibling", but I realized that since it starts at the first element within the div then it would begin leaking out and trying to identify the previous element outside of the div. I decided to use a for loop that creates a list of the elements with the specific class name, which works as intended. It begins to run into issues again, though, when it reaches the beginning or the end of the list. I assumed that "[i - 1]" would automatically bring it to the last element if the current was the one at the beginning of the list, and that "[i + 1]" would automatically bring it to the first element if the current was the one at the end of the list. It seems that is not the case.
Is anyone able to help me figure this out? It would be much appreciated.
Note: For the sake of simplicity, I didn't include the JavaScript code that makes it switch between items within the div. That part is fully functional so I don't believe it should affect the underlying concept of this problem.
My Code:
HTML:
<div class="items">
<div id="current-item" class="current-div-item"></div>
<div id="item" class="div-item"></div>
<div id="item" class="div-item"></div>
<div id="item" class="div-item"></div>
<div id="item" class="div-item"></div>
</div>
Javascript:
var divItems = document.getElementsByClassName('div-item'); // Gets number of elements with the specific class.
for (i = 0; i < divItems.length; i++) { // Creates list of elements with the specific class.
if (divItems[i].classList.contains('current-div-item')) { // If it is the current item, then do this:
var next = divItems[i + 1] // Find the next element in the list
var previous = divItems[i - 1] // Find the previous element in the list
next.id = 'next-item' // Change the next element's ID to "next-item"
previous.id = 'previous-item' // Change the previous element's ID to "previous-item"
}
}
You are wanting the items to wrap around that isn't going to happen. For the first item the previous item will be index -1 and for the last item the next index will be 1 larger than the actual number of items in the array.
If you add in a ternary you can get the values to wrap.
var prevIndex = (i === 0) ? divItems.length - 1 : i - 1;
var nextIndex = (i === divItems.length - 1) ? 0 : i + 1;
var next = divItems[prevIndex] // Find the next element in the list
var previous = divItems[nextIndex] // Find the previous element in the list
Based on your HTML code, in logic JS to fetch the all the items based in class it would not fetch the current-div-item as you have written logic to fetch only div-item. So I assume that you also need to change the HTML code. As per my understanding about your requirement I have done some changes and uploading the modified code. Which is working as per you requirement.
HTML:
<div id="current-div-item" class="div-item">Current</div>
<div id="item" class="div-item">Div1</div>
<div id="item" class="div-item">Div2</div>
<div id="item" class="div-item">Div3</div>
<div id="item" class="div-item">Div4</div>
Java Script:
var divItems = document.getElementsByClassName('div-item'); // Gets number of elements with the specific class.
for (i = 0; i < divItems.length; i++) {
if (divItems[i].id=='current-div-item') {
var next;
if (i == divItems.length-1)
next = divItems[0];
else
next = divItems[i + 1];
var previous;
if (i == 0)
previous=divItems[divItems.length-1];
else
previous = divItems[i - 1] // Find the previous element in the list
next.id = 'next-item' // Change the next element's ID to "next-item"
previous.id = 'previous-item' // Change the previous element's ID to "previous-item"
}
}
Attached the screenshot of the modified elements id for your reference

How to check last element has a css class or not?

I am adding class to these elements one by one based on user input. When I reached the last span element of this section, i need to give pop up. How to check that this last span has added a css class?
<section id="word-section"><span class="incorrect-word-c">ਪਰਕੋ</span><span class="current-word">ਚੇਤਕ</span><span>ਚਰਚ</span><span>ਪਰਕ</span><span>ਰੋਕ</span><span>ਰੇਤ</span><span>ਕਰੋ</span><span>ਚਟਪਟ</span><span>ਤਕ</span><span>ਰੁਤ</span><span>ਚਰਚ</span><span>ਰੋਕੋ</span><span>ਰਕਤ</span><span>ਰੋਕ</span><span>ਚਰਚ</span><span>ਪਰਕ</span><span>ਰੇਤ</span><span>ਪਰਕ</span><span>ਪਰਕ</span><span>ਪਰਤ</span><span>ਕਿ</span><span>ਰੋਕ</span><span>ਚੋਕਰ</span><span>ਰਕਤ</span><span>ਕਿ</span><span>ਰੋਕੋ</span><span>ਰੇਤ</span></section>
var remaining = $('#word-section > span').not('.current-word').length;
This command will find all spans that are direct children of the word-section section. It then filters to only include those that do not have the current-word class, and get the length (count) of them.
If remaining is zero, they all have the class.
To answer the specific question
Check if last element has a css class or not
you can use:
$("#word-section > span:last").hasClass("current-word")
this will:
find word-section
get all direct-descendant spans
limit the spans to the last one :last
check if that last one has class current-word
There's lots of different ways to do this, eg:
$("#word-section").find(">span").last().is(".current-word")
$("#word-section > span.current-word:last").length == 1
$("#word-section > span.current-word").nextAll().length == 0
Example snippet:
if ($("#word-section > span:last").hasClass("current-word")) {
// show popup
console.log("example: last word is current-word");
}
else {
console.log("example: more words to go");
}
if ($("#word-section-sample2 > span:last").hasClass("current-word")) {
// show popup
console.log("sample2: last word is current-word");
}
else {
console.log("sample2: more words to go");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section id="word-section"><span class="incorrect-word-c">ਪਰਕੋ</span><span class="current-word">ਚੇਤਕ</span><span>ਚਰਚ</span><span>ਪਰਕ</span><span>ਰੋਕ</span><span>ਰੇਤ</span><span>ਕਰੋ</span><span>ਚਟਪਟ</span><span>ਤਕ</span><span>ਰੁਤ</span><span>ਚਰਚ</span><span>ਰੋਕੋ</span><span>ਰਕਤ</span><span>ਰੋਕ</span><span>ਚਰਚ</span><span>ਪਰਕ</span><span>ਰੇਤ</span><span>ਪਰਕ</span><span>ਪਰਕ</span><span>ਪਰਤ</span><span>ਕਿ</span><span>ਰੋਕ</span><span>ਚੋਕਰ</span><span>ਰਕਤ</span><span>ਕਿ</span><span>ਰੋਕੋ</span><span>ਰੇਤ</span></section>
<section id="word-section-sample2"><span class="incorrect-word-c">ਪਰਕੋ</span><span>ਚੇਤਕ</span><span>ਚਰਚ</span><span>ਪਰਕ</span><span>ਰੋਕ</span><span>ਰੇਤ</span><span>ਕਰੋ</span><span>ਚਟਪਟ</span><span>ਤਕ</span><span>ਰੁਤ</span><span>ਚਰਚ</span><span>ਰੋਕੋ</span><span>ਰਕਤ</span><span>ਰੋਕ</span><span>ਚਰਚ</span><span>ਪਰਕ</span><span>ਰੇਤ</span><span>ਪਰਕ</span><span>ਪਰਕ</span><span>ਪਰਤ</span><span>ਕਿ</span><span>ਰੋਕ</span><span>ਚੋਕਰ</span><span>ਰਕਤ</span><span>ਕਿ</span><span>ਰੋਕੋ</span><span class="current-word">ਰੇਤ</span></section>

If container has children of a certain class

I'm working on a live search function, but I need to hide any containers that do not have a match.
This is a sample of how the containers are populated if nothing is entered in the search bar. EDIT: This will be identical even if there is a string in the search bar. fadeOut() hides the element, doesn't remove it.
<div id="Alabama_container" class="state-container">
<h1>Alabama</h1>
<div id="330_store-object" class="store-object" style="">
<h4>Store 330 - Birmingham</h4>
<p>(205) 981-1320</p>
<p>5201 US-280, Birmingham, AL 35242, USA</p>
<button id="330_store-object-link" class="button">View on Map</button><button id="330_store-object-floorPlan" class="button">Floorplans</button>
</div>
<div id="337_store-object" class="store-object" style="">
<h4>Store 337 - Dothan</h4>
<p>(334) 671-1370</p>
<p>4401 Montgomery Hwy #300, Dothan, AL 36303, USA</p>
<button id="337_store-object-link" class="button">View on Map</button><button id="337_store-object-floorPlan" class="button">Floorplans</button>
</div>
</div>
The state-container elements are generated on the DOM first then store-object elements are appended to the appropriately named state-container.
Search Function Sample:
$(document).ready(function () {
$("#store-search").keyup(function () {
var filter = $(this).val(),
count = 0;
$(".store-object").each(function () {
// If the store object doesn't match, remove it
if ($(this).text().search(new RegExp(filter, "i")) < 0) {
$(this).fadeOut();
// Show the store objects that do match the query
} else {
$(this).show();
count++;
}
});
// Results counter for troubleshooting
var numberItems = count;
$("#filter-count").text(count + "Results Founds");
});
});
My search function simply uses filter to determine any matching strings within the store-object elements and hides any that don't match. However, the matches still reside in their state-container so what you end up with is a list of states without any results inside.
What I want to do is loop through state-container elements and determine if it contains any store-object children so I can handle it appropriately. What would I use to achieve this?
There are several different ways to achieve what you want. One of which would be using the :visible selector and then hiding the state-container on an empty set.
$('.state-container').each(function(){
if($(this).find('.store-object:visible').length === 0){
$(this).hide();
}
});
Keep in mind, you'll need to run that after all of the children's fadeOut animations have completed.
Another approach would be to keep a tally of the hidden elements as you go through the search, and if all children were hidden remove the parent.
$(document).ready(function () {
$('.state-container').each(function(){
$(this).data('total', $(this).find('.store-object').length);//set a count of total
});
$("#store-search").keyup(function () {
var filter = $(this).val(),
count = 0;
//reset the hidden count for the states
$('.state-container').each(function(){
$(this).data('hidden', 0);//initialize to 0
$(this).show();
});
$(".store-object").each(function () {
var parent = $(this).parent();
// If the store object doesn't match, remove it
if ($(this).text().search(new RegExp(filter, "i")) < 0) {
$(this).fadeOut();
parent.data('hidden', parent.data('hidden') + 1);//increment hidden count
// Show the store objects that do match the query
} else {
$(this).show();
count++;
}
if(parent.data('hidden') == parent.data('total')){
parent.hide();
}
});
// Results counter for troubleshooting
var numberItems = count;
$("#filter-count").text(count + "Results Founds");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id='store-search' />
<div id="Alabama_container" class="state-container">
<h1>Alabama</h1>
<div id="330_store-object" class="store-object" style="">
<h4>Store 330 - Birmingham</h4>
<p>(205) 981-1320</p>
<p>5201 US-280, Birmingham, AL 35242, USA</p>
<button id="330_store-object-link" class="button">View on Map</button><button id="330_store-object-floorPlan" class="button">Floorplans</button>
</div>
<div id="337_store-object" class="store-object" style="">
<h4>Store 337 - Dothan</h4>
<p>(334) 671-1370</p>
<p>4401 Montgomery Hwy #300, Dothan, AL 36303, USA</p>
<button id="337_store-object-link" class="button">View on Map</button><button id="337_store-object-floorPlan" class="button">Floorplans</button>
</div>
</div>
You can check if store-container has store-object and then only loop through them like:
$(".store-container").find(".store-object").length &&
$(".store-object").each(function () {
After your edit, I could say that you should check for visible length like:
$(".state-container").find(".store-object:visible").length &&
But, I would still say that you don't need to check anything because you're already checking for the condition that if it's visible then only fadeOut. That is, even if this is hidden, there's nothing problem using fadeOut. But what I can say is that you can pause the search execution:
setTimeout(()=>{
// your each function
}, 600);

Target previous element with jQuery

I'm creating portfolio section where every portfolio item shows as an image and every portfolio item has its own div which is hidden and contains more information about that item. When the user clicks on some portfolio item (image) div with more information for that item is shown. Each div with more info has two classes, portf-[nid] and portf ([nid] is Node ID, I work in Drupal and this class with [nid] helps me to target portfolio item with more info div for that item).
Each of the more info divs contains arrows for item listing (next and previous) and I need to get them function, so when the user clicks on previous I need to hide current and show the previous item if it exists(when clicks on next to hide current and show next item if it exists).
My markup looks like:
<div class="portf-3 portf">
//some elements
</div>
<div class="portf-6 portf">
//some elements
</div>
<div class="portf-7 portf">
//some elements
</div>
My question is how to hide the div I'm currently on and show the previous (or next). For example: if it is currently shown div with class portf-6 and user clicks on previous arrow, this div is being hidden and div with class portf-3 is being shown.
It's not the problem to hide/show the div but how to check if there is the div above/below the current div and to target that div above or below the current div?
Here you are:
function GoToPrev()
{
var isTheLast = $('.portf:visible').prev('.portf').length === 0;
if(!isTheLast)
{
$('.portf:visible').hide().prev().show();
}
}
function GoToNext()
{
var isTheLast = $('.portf:visible').next('.portf').length === 0;
if(!isTheLast)
{
$('.portf:visible').hide().next().show();
}
}
To check if prev / next element is present or not, you can make use of .length property as shown below
if($('.portf:visible').prev('.portf').length > 0) // greater than 0 means present else not
same for next element
if($('.portf:visible').next('.portf').length > 0)
As you also need to update the next and previous buttons, I would suggest a more structured approach to the whole thing:
function update(delta) {
var $portfs = $('.portf');
var $current = $portfs.filter(':visible');
var index = $portfs.index($current) + delta;
if (index < 0) {
index = 0;
}
if (index > $portfs.length){
index = $portfs.length;
}
$current.hide();
$portfs.eq(index).show();
$('#prev').toggle(index > 0);
$('#next').toggle(index < $portfs.length-1);
}
$('#prev').click(function () {
update(-1);
});
$('#next').click(function () {
update(1);
});
// Hide all initially
$('.portf').hide();
// Show the first with appropriate logic
update(1);
JSFiddle: http://jsfiddle.net/TrueBlueAussie/xp0peoxw/
This uses a common function that takes a delta direction value and makes the decisions on range capping an when to hide/show the next/previous buttons.
The code can be shortened further, but I was aiming for readability of the logic.
If the next/prev buttons are correctly shown the range checking is not needed, so it simplifies to:
function update(delta) {
var $portfs = $('.portf');
var $current = $portfs.filter(':visible');
var index = $portfs.index($current) + delta;
$current.hide();
$portfs.eq(index).show();
$('#prev').toggle(index > 0);
$('#next').toggle(index < $portfs.length-1);
}
JSFiddle: http://jsfiddle.net/TrueBlueAussie/xp0peoxw/1/

How to display search results onkeyup?

I have a search box that as the user types letters into the search box, we will filter and display the results. However, as the user types each letter the search results are getting toggled between showing and hiding. I am very new to JS so I hope it could be an easy fix.
Here is my HTML:
See Below
Here is my toggle JS:
See Below
How can I tweak the JS to not toggle back and forth?
//Here are my edits to help answer the question. This is the JS and HTML I am using to display the results:
HTML:
<div class="friendssearch" onclick="toggle_visibility('friendslist');">
<div class="friendssearch">
<div id="friendssearchbox"></div>
</div>
<ul id="friendslist" style="display: none;">
<li>
<a href="#">
<div class="friendsflybox" title="Friends Name">
<p class="friendsflyboxname">Ryan Bennett</p>
</div>
</a>
</li>
</ul>
</div>
Javascript:
<script>
(function ($) {
// custom css expression for a case-insensitive contains()
jQuery.expr[':'].Contains = function(a,i,m){
return (a.textContent || a.innerText ||
"").toUpperCase().indexOf(m[3].toUpperCase())>=0;
};
function listFilter(header, list) { // header is any element, list is an unordered list
// create and add the filter form to the header
var form = $("<form>").attr({"class":"filterform","action":"#"}),
input = $("<input>").attr({"class":"filterinput clearFieldBlurred
ClearField","type":"text", "value":"Start typing a Name"});
$(form).append(input).appendTo(header);
$(document).ready(function() {
$('.clearField').clearField();
});
$(input)
.change( function () {
var filter = $(this).val();
if(filter) {
// this finds all links in a list that contain the input,
// and hide the ones not containing the input while showing the ones that do
$(list).find("a:not(:Contains(" + filter + "))").parent().slideUp();
$(list).find("a:Contains(" + filter + ")").parent().slideDown();
} else {
$(list).find("li").slideDown();
}
return false;
})
.keyup( function () {
// fire the above change event after every letter
$(this).change();
});
}
//ondomready
$(function () {
listFilter($("#friendssearchbox"), $("#friendslist"));
});
}(jQuery));
</script>
You'll need to do something similar to the code I have posted below. This assumes that you can access the object that contains the search results.
function toggle_visibility(id)
{
//Check if there are any search results to display
var searchResultLength = document.getElementById(searchResultID).innerHTML.length;
if (searchResultLength > 0) // display div
{
var e = document.getElementById(id);
e.style.display = 'block';
}
else //No search results, hide div
{
e.style.display = 'none';
}
}
Basically, you need to determine if you have search results to display before you attempt to toggle the div's visibility.
//EDIT AFTER COMMENTS
OK, so it looks like the results are adding li's to the ul. So, assuming that the code is taking away the li's as well as adding them, you should be checking for the number of elements in the ul == 0. See below.
$('#friendslist > li').length
To be honest, I'm having a bit of difficulty trying to determine exaclty what the code is
doing. I'm certainly not a jquery expert. I would say if the above code doesn't get you going in the right direction, I'm out of ideas.
If you're only wanting it to display when you enter the field use the onFocus="method()" attribute. followed by onBlur="method()". this will display the block when you enter the field and hide it when you leave.
<input id="searchbox" type="text" onFocus="toggle_visibility('friendslist');" onBlur="toggle_visibility('friendslist')">
<ul id="friendslist" style="display: none;">
<!--search results HTML-->
</ul>
teach a man to fish: http://www.w3schools.com/jsref/dom_obj_event.asp
// EDIT
I think Quickfire's answer is the best solution. but as I understand it you want you results to show/hide, so I modified his method to better suit your markup.
function toggle_visibility(id){
//Get the total number of <li> within my search result
var results=document.getElementById(searchResultID).childNodes.length;
if (results > 0){ // we have more than 0 results
var e = document.getElementById(id);
e.style.display = 'block'; // show the element
}else{ //No search results, hide div
e.style.display = 'none'; //hide the element
}
}

Categories