If container has children of a certain class - javascript

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);

Related

using OOP on .click function in javascript

I am making a webpage that has a baseball strikezone with 25 buttons that will be clickable in 25 locations. I need to know if there is a easier way to do this then what I am doing. Maybe something that will take up far less lines. The button is clicked and then the counter is added by one to another table.
$('#one').click(function(){
counter++;
$('#ones').text(counter);
});
var countertwo = 0;
$('#two').click(function(){
countertwo ++;
$('#twos').text(countertwo);
});
A bit of a guess here, but:
You can store the counter on the button itself.
If you do, and you give the buttons a common class (or some other way to group them), you can have one click handler handle all of them.
You can probably find the other element that you're updating using a structural CSS query rather than id values.
But relying on those ID values:
$(".the-common-class").click(function() {
// Get a jQuery wrapper for this element.
var $this = $(this);
// Get its counter, if it has one, or 0 if it doesn't, and add one to it
var counter = ($this.data("counter") || 0) + 1;
// Store the result
$this.data("counter", counter);
// Show that in the other element, basing the ID of what we look for
// on this element's ID plus "s"
$("#" + this.id + "s").text(counter);
});
That last bit, relating the elements by ID naming convention, is the weakest bit and could almost certainly be made much better with more information about your structure.
You can use something like this:
<button class="button" data-location="ones">One</button>
...
<button class="button" data-location="twenties">Twenty</button>
<div id="ones" class="location">0</div>
...
<div id="twenties" class="location">0</div>
$('.button').on('click', function() {
var locationId = $(this).data('location')
, $location = $('#' + locationId);
$location.text(parseInt($location.text()) + 1);
});
Also see this code on JsFiddle
More clean solution with automatic counter
/* JS */
$(function() {
var $buttons = $('.withCounter'),
counters = [];
function increaseCounter() {
var whichCounter = $buttons.index(this)+1;
counters[whichCounter] = counters[whichCounter] ? counters[whichCounter] += 1 : 1;
$("#counter"+whichCounter).text(counters[whichCounter]);
}
$buttons.click(increaseCounter);
});
<!-- HTML -->
<button class="withCounter">One</button>
<button class="withCounter">Two</button>
<button class="withCounter">Three</button>
<button class="withCounter">Four</button>
<p id="counter1">0</p>
<p id="counter2">0</p>
<p id="counter3">0</p>
<p id="counter4">0</p>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Javascript live search not responding?

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")

Flipping with navigation keys divs that are :checked in input

I need the next & previous buttons to navigate through the divs that was selected in checkboxes. That means that user selects several options press the start button and do some actions in first selected option, then he press next and navigates to next div and again do some actions.
$(document).ready(function () {
$('#roomsubmit').click(function () {
$(".room").hide();
if ($("#node").is(':checked')) {
$("#hallway").show();
$("#hallway").addClass("roomNew");
} else if ($("#node-2").is(':checked')) {
$("#livingroom").show();
$("#livingroom").addClass("roomNew");
} else if ($("#node-3").is(':checked')) {
$("#bedroom").show();
$("#bedroom").addClass("roomNew");
} else if ($("#node-4").is(':checked')) {
$("#playroom").show();
$("#playroom").addClass("roomNew");
}
});
$(function () {
$(".swap").on({
click: function () {
var parent = $(this).closest('.roomNew');
parent.css('display', 'none');
if (this.id == 'previousBtn') {
parent.prev('.roomNew').css('display', 'block');
} else {
parent.next('.roomNew').css('display', 'block');
}
}
});
});
});
.room {
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<label for="node">Hallway
<input type="checkbox" id="node" />
</label>
<label for="node-2">Livingroom
<input type="checkbox" id="node-2" />
</label>
<label for="node-3">Bedroom
<input type="checkbox" id="node-3" />
</label>
<label for="node-4">Playroom
<input type="checkbox" id="node-4" />
</label>
<button id="roomsubmit">Start calculation</button>
<div id="hallway" class="room">Works in hallway
<button class="swap previousBtn" id="previousBtn">prev</button>
<button class="swap nextBtn" id="nextBtn">next</button>
</div>
<div id="livingroom" class="room">Works in livingroom
<button class="swap previousBtn" id="previousBtn">prev</button>
<button class="swap nextBtn" id="nextBtn">next</button>
</div>
<div id="bedroom" class="room">Works in bedrrom
<button class="swap previousBtn" id="previousBtn">prev</button>
<button class="swap nextBtn" id="nextBtn">next</button>
</div>
<div id="playroom" class="room">Works in playroom
<button class="swap previousBtn" id="previousBtn">prev</button>
<button class="swap nextBtn" id="nextBtn">next</button>
</div>
jsfiddle for the above code
I have something for you, Roby. Sorry for delay - had to work it out.
jsFiddle Demo
First, there are now two arrays: arrRooms (an array of objects which map the nodename to the room), and newRooms (an array to store checkmarked rooms - poor name, but oh well).
The arrRooms array is used to get the room name when given the node. This eliminated all those if-else lines.
A new function $('input:checkbox').click was created to add/remove the checked/unchecked nodes from the newRooms array. This leaves you with an array containing just the checked rooms.
Next, the #roomsubmit.click function was simplified to use the above arrays. All it does now is (1) grab the first item in the newRooms array (the checked rooms) (2) display that room's DIV, and (3) remove that item from the newRooms array. This creates a "cafeteria plate" scenario where each time you click #roomsubmit ("Start Calculation" button), the next checked room is displayed.
Important: Note that you have several elements with the same ID (id="nextBtn" and id="previousBtn"). Not allowed, I'm afraid. Every ID must be completely unique in the DOM. However, there is no need to use IDs at all since they are not referenced in the code at the moment. The jQuery selector uses the class, so just delete the ID attributes from the HTML.
By the way, to make the previous button work, you can modify your swap function to work with the above, or else change your approach completely and just create another empty array and when you delete a room from the newRooms[] array, add it into the prevRooms[] array. When the previous button is clicked, grab the room-to-display from the prevRooms[] array, delete it from there, and stick it back into the newRooms[] array. You will work it out... (In fact, you may need three variables: prevRooms array, currRoom var, and newRooms array --- put some legos on a desk to represent the checked rooms, and use three circles to represent the three arrays - and imagine clicking the next/prev buttons and moving the curr room lego from one pile into the next, and you'll quickly work out how to do this.)
javascript/jQuery code:
var tmp;
var arrRooms={'node':'hallway','node-2':'livingroom','node-3':'bedroom','node-4':'playroom','node-5':'cabinet','node-6':'kitchen','node-7':'bathroom','node-8':'wc'};
var newRooms=[];
$('input:checkbox').click(function(){
if ($(this).is(':checked')) {
newRooms.push(this.id);
//alert( JSON.stringify(newRooms) );
}else{
newRooms.splice(newRooms.indexOf(this.id),1); //delete from newRooms
//alert( JSON.stringify(newRooms) );
}
});
$('#roomsubmit').click(function () {
$(".room").hide();
tmp = arrRooms[newRooms[0]];
//alert('tmp = ' +tmp);
$('#' +tmp).addClass('roomNew').show();
newRooms.splice(0,1);
//alert( JSON.stringify(newRooms) );
});
$('.nextBtn').click(function(){
$('#roomsubmit').click();
});
$(function () {
$(".swap").on({
click: function () {
var parent = $(this).closest('.roomNew');
parent.css('display', 'none');
if (this.id == 'previousBtn') {
parent.prev('.roomNew').css('display', 'block');
} else {
parent.next('.roomNew').css('display', 'block');
}
}
});
});

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
}
}

jQuery Carousel. How to show the Next or Previous Element only

I have a jQuery problem, and I've really tried everything I know (i am so newbie at this) so ..
The problem in short is I am doing a simple carousel-like effect. I am using this code.
(The div .showarea is the DIV which needs to be rotated (next/prev) but I want to keep only one div shown at a time.)
This is the html markup.
<div class="maincarousel">
<div class="showarea"><img src="img/sampleshow.png" alt="" title="" /></div>
<div class="showarea"><img src="img/sampleshow2.png" alt="" title="" /></div>
<div class="showarea"><img src="img/sampleshow3.png" alt="" title="" /></div>
</div>
This is my jquery attempt
$('.showarea').hide();
$('.showarea:first').fadeIn(500);
$('.maincarousel a').click(function () {
if ($(this).attr('href') == '#carouselNext') {
$('.showarea').hide();
$('.showarea').next('.showarea').fadeIn(500);
}
if ($(this).attr('href') == '#carouselPrev') {
$('.showarea').hide();
$('.showarea').prev('.showarea').fadeIn(500);
}
});
Unfortunately, next() and prev() won't display the next element only, but all next elements and same thing for prev(). Any quick workaround..
Can someone help me on this,
Thanks
You could try using .eq(0) to select the first element in the collection given to you by .prev() and .next().
Note that .next() and .prev(), like most jQuery methods, are operating on a collection. So if your selector '.showarea' is selecting multiple elements, then .next() will select the next sibling element for each element selected by '.showarea', and similarly for .prev().
if ($(this).attr('href') == '#carouselNext') {
$('.showarea').hide();
var el = $('.showarea').next('.showarea').eq(0);
if (el.length) {
el.fadeIn(500);
}
}
if ($(this).attr('href') == '#carouselPrev') {
$('.showarea').hide();
var el = $('.showarea').prev('.showarea').eq(0);
if (el.length) {
el.fadeIn(500);
}
}
The below will rotate so if you are at the first item pressing back will then show the last item...
Demo here
$('div.showarea').fadeOut(0);
$('div.showarea:first').fadeIn(500);
$('a.leftarrow, a.rightarrow').click( function (ev) {
//prevent browser jumping to top
ev.preventDefault();
//get current visible item
var $visibleItem = $('div.showarea:visible');
//get total item count
var total = $('div.showarea').length;
//get index of current visible item
var index = $visibleItem.prevAll().length;
//if we click next increment current index, else decrease index
$(this).attr('href') === '#carouselNext' ? index++ : index--;
//if we are now past the beginning or end show the last or first item
if (index === -1){
index = total-1;
}
if (index === total){
index = 0
}
//hide current show item
$visibleItem.hide();
//fade in the relevant item
$('div.showarea:eq(' + index + ')').fadeIn(500);
});

Categories