Javascript: How to perform count on visible elements only? - javascript

I'm using jQuery to get a string from a search field and hide items that don't match. It loops through a list of divs and uses $(this).fadeOut(); to hide those elements.
This works very well, but I would like to add further searches within that search. I've added an extra search field, but of course it doesn't inherit the fade outs from the previous search and it starts again from the beginning.
I need a way to specify to the searches to only search visible elements of the list. This needs to work in reverse order as users might enter in the the second search field, then the first.
Here's a JSFiddle of my code illustrating the problem
JSFiddle Here
And a code snippet of one search function
$("#filter").keyup(function () {
var filter = $(this).val(),
count = 0;
$(".records2 div").each(function () {
// If the list item does not contain the text phrase fade it out
if ($(this).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++;
}
});
});

You can use:
element.is(":visible")
To test if a given element is visible or not.
So in your case you'd just do:
if ($this).is(":visible")); {count++;}
Or you can add ":visible" to the end of your selectors to only pick the visible items:
$(".someselector div:visible").each(...);
Edit: I just checked the jquery documentation. You get better performance if you do:
$(".someselector div").filter(":visible").each(...);
This is because :visible isn't part of the CSS specification so jquery has to implement it manually.

Related

jQuery .remove() Not Working After Valid Selection of Element

JSFiddle: https://jsfiddle.net/coh1xr77/5/
I need to delete an <LI> DOM Element correctly selected with a Selector based on its exact content. My list contains a set of Time LI's and my choice is to delete the first one in the list, 12:15am, based on the exact text match, when I click the button.
I can see that my selection is correct because I'm getting an [Object] reference in the alert box, rather than "Undefined".
However, the subsequent remove() on this element does nothing: the element remains.
var myselection = '12:15am';
$('#remove').click(function() {
var current = $('.ui-timepicker-list li').filter(function() {
return $(this).text() === myselection;
});
alert('current = ' + current); // This works, element found
$(current).remove(); // This does nothing (or doesn't remove properly)
});
You need to change the condition to check if the li's innerText starts with the selected time string. Like: $(this).text().indexOf(myselection) == 0
Here's the updated fiddle: https://jsfiddle.net/coh1xr77/11/
Update
Considering that all time values have the bracketed relative time strings at the end, you could try splitting based on that bracket (, and compare with the first part of that string. Like: $(this).text().split('(')[0].trim() == myselection
Here's the fiddle with that: https://jsfiddle.net/coh1xr77/12/
Update 2
If you are absolutely certain that the structure of li elements will not change, you could access the text using the childNodes. Like: $(this)[0].childNodes[0].textContent == myselection;
Here's the updated fiddle: https://jsfiddle.net/coh1xr77/14/

Searching for item in each list item

I am working on a piece of code to check if there is in the list item a div called star rating. If it doesnt excist, add to the price tag an extra margin top (so i can level out these items). My JQuery is as followed
$(document).ready(function() {
$("li.product").each(function(){
if($(".star-rating").length === 0) {
$("span.price").css({"margin-top" : "1em"});
}
});
});
This code works fine to a certain point. What it technically does is it doesnt check the specific list item but the whole document. Is there a way I can just check the specific list item and add to the span.pricein that item the css? cause now it finds 4 times the star-rating (4 list items), while it is only in one list item.
Search under each "li.product":
$("li.product").each(function(){
if($(this).find(".star-rating").length === 0) {
$(this).find("span.price").css({"margin-top" : "1em"});
}
});
if($(".star-rating",this).length === 0) {
$("span.price",this).css({"margin-top" : "1em"});
}
Add context parameter to jQuery method
$('li.product').not(':has(.star-rating)').find("span.price").css({"margin-top" : "1em"});
Without "if" and "each" that's what Jquery is for...

Check if a div has any children

I have the below code that checks to see if any of my divs has the class "wrong" and if so it shows the jQuery UI dialog box. However i want to extend the code so that it checks those divs and if there are any that are empty it should not show the dialog box.
I've looked around and some people are suggesting using children().length > 0 to accomplish this, but I'm not sure how to write this with my code.
js:
$("#run").click(function() {
if ($("[id^='Drop']").hasClass("wrong")) {
$("#dialog1").dialog("open");
}
});
The following selectors could be used to test if an element is empty or not:
:empty matches elements that have no children (thus, empty)+
:parent matches elements that have children+
Now, rephrasing your statement:
... so that it checks those wrong divs and if
there are any that are empty they are all full it should
not show the dialog box.
You would write:
var $allWrong = $("id[^='Drop'].wrong"),
$notEmpty = $wrong.filter(":parent");
if ($allWrong.length && $allWrong === $notEmpty) {
// show dialog
}
+ Text nodes are counted when counting children. <span> </span> contains a text node which contains a whitespace. Therefore it matches :parent and does not match :empty.
The logic consists of two parts:
Finding elements with id property starting with "Drop" and having the .wrong class.
Checking whether any of those elements are empty.
To do this, I'm saving the first step in an intermediate variable, before doing the final condition:
var $wrongFields = $('[id^="Drop"].wrong');
if ($wrongFields.length && !$wrongFields.filter(':empty').length) {
// at least one field exists with:
// - id starting with "Drop"
// - class of "wrong"
// and none of those fields are empty
$("#dialog1").dialog("open");
}
Demo
This would also work
$("#run").click(function(){
if ($("[id^='Drop']").hasClass("wrong") && $("[id^='Drop'].wrong:empty").length ) {
$( "#dialog1" ).dialog( "open" );
}
});

Use array to show elements

I've got a problem that I can't figure out and was wondering if you good people could help out? I'm building a filter system that uses data options on the tags.
The nav elements add to an array when pressed and take that option out
of the array when pressed again.
You may notice that the first set allows for combination and the date range doesn't. This is intentional. My problem lies with asking the script to show the elements in the #container that match the data tag when pressed - I want to show the li elements within #container that match the data-season="" or the data-date="".
in the seasons script this is my problematic piece of script....
if (typeof $("#container li").data('season' == showseason ) )
{
$(this).show();
}
I've tried various ways but I'm now just going in loops getting more confused with each attempt. HELP :)
Jsfiddle Demo
You should change that if statement. remove the typeof keyword, and compare the data value.
if ($("#container li").data('season') == showseason )
{
// do something here
}
Or better yet, iterate through each of the li within #container and get the data-season value.
$("#container li").each(function(){
var season = $(this).data("season");
if(season == showseason)
$(this).show();
else
$(this).hide();
});
Please refer to the updated fiddle: http://jsfiddle.net/b2eh2w07/11/

remove delete button on first set of fields

http://jsfiddle.net/NzbRQ/2/
I allow the user to add multiple rows of fields, but I do not want to include a delete link on the very first row of fields, so they can't delete all the fields.
Also, how do I limit it to only 3 rows of fields?
Try this fiddle: Fiddle
For the first part of hiding the delete on the first row, I called the following on page load:
$(".removeoutcome").hide();
Then to make sure they can't add more than 3 or delete the last one, I've added length checks in your click methods, see:
$('.addoutcome').live('click', function() {
if ($(".outcomegroup").length < 3) {
$('#template').clone().removeAttr('id').insertAfter($(this).closest('.outcomegroup')).find('.minus').show();
renumber();
}
});
$('.removeoutcome').live('click', function() {
if ($(".outcomegroup").length > 1) {
$(this).closest('.outcomegroup').remove();
renumber()
}
});
Also, on a side note, live is deprecated now, so if you're using jQuery 1.7, change these methods to on or if you're pre-1.7, use delegate.
You can just hide the del for first element and limit it to add only 3 more set using the following code
var count = 3;
$('.minus').first().hide();
$('.addoutcome').live('click', function() {
count--;
if(count < 0 )return;
$('#template').clone().removeAttr('id').insertAfter($(this).closest('.outcomegroup')).find('.minus').show();
});
here is the working fiddle http://jsfiddle.net/joycse06/uW9NQ/
Updated: http://jsfiddle.net/NzbRQ/5/
First off, ditch .live. I added the section to give a more specific selector than body, but there's probably something better that you can use in your original DOM.
Just don't remove the last row with some simple logic. Your logic for showing the future "del" link was actually already there! You don't even really need the last-row-removal logic at all since just not displaying "del" is enough, but I was just being thorough.
I don't know why anyone haven't paid close attention to this line:
.find('.minus').show();
where he definitely was un-hiding the del element. In short, the only thing you need to do is add the proper CSS rule:
.minus { display: none; }
and that's it, the first element won't show a del link and the others will.
The limit to three elements simply.
$("[parent element]").on('click', '.addoutcome', function() {
if($('.addoutcome').length > 2) return;
...
});
A better selector [parent selector] is needed and depends totally in your layout. Basically, it is the element that wraps all these elements, the parent element of all of them.

Categories

Resources