Targeting $(this) within nested for each loops in jQuery - javascript

I'm trying to figure out, when iterating through some list items, how to target each "$(this)" equivalent within nested foreach loops. Here is an example of my problem:
$('li').each(function(){
// I believe $(this) would target each li item...
$(this).children("li").each(function(){
// ... but how can I target each of these li items? Doesn't $(this) target the original loop?
});
});

$('li').each(function(){
var $this = $(this);
$this.children("li").each(function(){
$this; // parent li
this; // child li
});
});

Don't use this! Use function parameters!
$('li').each(function(i, li){
$(li).children("li").each(function(ii, li2){
$(li)...
$(li2)...
});
});
This is more in keeping with the native JavaScript iterators.
...though an <li> can't be the direct child of another <li>

Look at the basic "prototypes" of jQuery functions (or methods, if you will):
$[jQobject].[func]([callback]);
The callback is the function that will be invoked in the context of the jQ object. The context being this, obviously. Put simply that means that:
$('#foo').click(function(){});
/\ /\
|| Is the context ||
=====================
The same applies to your case, regardless of the loops being nested or not:
$('ul').each(function()
{
//this is ul
var that = this;//you'll often see code like this
$('li', this).each(function()
{
//this is li
//that is parent ul
});
});

but how can I target each of these li items? Doesn't $(this) target the original loop?
Nope.
this comes from the function you're directly in.

Nope, this refers to each of the child <li> items. Try it out.
Most (if not all) DOM-interacting jQuery callbacks set this to to the DOM element that you're working with.
You could also write:
$('li').children("li").each(function(){
var $this = $(this);
});

Related

Check if list element is visible (jquery.visible)

I'm trying to check if each element of an ul list is visible using the jquery.visible plugin. The problem is that the script does not handle each "li" element as independent, so putting this:
var element = $("ul li");
if (element.visible(true)) {
element.removeClass("hidden");
}
Removes the "hidden" class of all elements at the same time.
Any ideas?
You are initializing element as an array, so the name is misleading, and it may be throwing you off later in the code.
You want something like this (untested):
var arrElements = $("ul li");
arrElements.each(function() {
if ($(this).visible(true)) {
$(this).removeClass("hidden");
}
});
Note that I am using the each method and $(this) to act on only one li element at a time.
How about checking just the css property:
if(element.css('display') != 'none')

Toggle between selected classes

I find my self doing this a lot:
$(document).on("click","li",function(){
$(".selected").removeClass("selected"); // Remove any old selected
$(this).addClass("selected"); // Apply selected to this element
});
Is there a better and less repetitive way of doing a task like this? Like toggle a class. Btw, only one element can be selected at a given time.
Thanks.
A more efficient way is to keep track of the last selected item:
var $selected = null;
$(document).on("click", "li", function() {
if ($selected) {
$selected.removeClass('selected');
}
$selected = $(this).addClass('selected');
});
Of course, this should work as long as that particular function is the only one that will ever add / remove the selected class.
This could optionally be wrapped inside a closure to remove the $selected variable.
Btw, using document as the anchor for your delegation isn't best practice. It's better to choose the nearest node that will not get removed from the document.
Update
As Kevin B has mentioned, you could eliminate the branch like so:
var $selected = $();
$(document).on("click", "li", function() {
$selected.removeClass('selected');
$selected = $(this).addClass('selected');
});
The ability to use $() was introduced in 1.4; before that you would use $([]).
You can do this:
<script>
$(document).ready(function(){
$(this).on("click", "li", function() {
$(this).addClass('selected').siblings().removeClass('selected');
});
});
</script>
After debating with Jack I propose mine.
Assuming your list is here :
var $myList = $('#list');
Then:
$myList.on("click","li",function(){
$(".selected",$myList).removeClass("selected"); // Remove any old selected
$(this).addClass("selected"); // Apply selected to this element
});
or
$myList.on("click","li",function(){
$(this).siblings(".selected").removeClass("selected"); // Remove any old selected
$(this).addClass("selected"); // Apply selected to this element
});
Your way of doing it is good enough for me but Jack's is faster and mine is in between both.
I like this one because you don't need to assume there will only be one selected element. And searching is faster when we provide context as far as I know
Thinking about this, you could keep your list elements in a variable, such as:
var $liElements = $('#yourContainer > li');
$(document).on("click","li",function(){
$liElements.not($(this)).removeClass("selected");
$(this).addClass("selected");
});
The notion of keeping track of the current element is the same as the other answers, but you can wrap this logic up cleanly in a function such as
function class_swapper=function(cls){
var cur;
return function(elt){
if (cur) { cur.classList.remove(cls); }
elt.classList.add(cls);
cur=elt;
};
};
A call to class_swapper returns a function used to actually apply the specified class to a particular element (and remove it from the previous one, which is remembered inside the function). You can use this as follows:
var swapper=class_swapper("selected");
swapper(elt1);
swapper(elt2);
or in terms of your example
$(document).on("click","li",function(){swapper(this);});
I've used classList.add and classList.remove, which is a classy way (ouch) of manipulating classes in modern browsers, but of course these could be replaced by jQuery's addClass etc. as necessary.

Javascript/html: How to store div, and hide its children later

I am storing a div which gets selected
var selectedCell = null;
$(".selectableBox").on('click', function (event) {
selectedCell = $(this);
}
Later I want to hide one of selectableCell's children name selectableCellChild
$('#deleteConfirmed').on('click', function (event) {
selectedCellList.($'selectableCellChild').hide();
});
How can I correctly hide this child div? I know the syntax of the above example isn't right, and I have tried it many ways including using children() and next() methods of selectedCellList
selectedCellList.find('{selectableCellChild}').hide();
Where selectableCellChild is a placeholder for the real selector of the cell.
I have tried it many ways including using children() and next()
children - traverse only one level deep.
find - traverse the all the DOM levels deep.
next select the next immediate sibling.
For the second part, this is what you want:
$('#deleteConfirmed').on('click', function (event) {
$(selectedCellList).find('.selectableCellChild').hide();
});
If I understood correctly, you are trying to hide the children of clicked div. Try like below,
var selectedCell = null;
$(".selectableBox").on('click', function (event) {
selectedCell = $(this);
}); //Your missed );
$('#deleteConfirmed').on('click', function (event) {
//v-- Changed from selectedCellList to selectedCell as this is the clicked div.
selectedCell.find('.selectableCellChild').hide();
//assuming selectableCellChild-^ is class of child elements in the clicked div
});
Use .find.
selectedCellList.find('selectableCellChild').hide(); // I hope selectableCellChild isn't your real selector, it won't work
Also, when declaring your variable, make it a jQuery object since you intend to store a jquery object in it to avoid undefined method errors.
var selectedCell = $();

How to get child elements of $self, jquery is OK

$('#cont > fieldset').each(
function(index){
var $self = $(this);
// Here how to get child elements? How to write this selector?
//$('$self > div') ?? this seems does not work.
});
$self.find("div"); // return all descendant divs
or:
$self.children("div"); // return immediate child divs
depending on whether you want immediate children or any descendants.
You can even do this to get immediate child divs, but children is prettier :
$self.find(">div");
Look at the .children method in jQuery. This will get direct children of the element, e.g.:
$self.children('div') // returns divs that are direct children
You can also use the similar .find method if you need to go deeper than one level.
$self.find('div') // returns divs that are direct children, or children of children
Also, you can select using $self as the context, like:
$('div', $self) //returns all divs within $self
using children
$(this).children('div')
or
using find
$(this).find('div');
look on this post
You can use the children() method, to get all immediate children of self.
var children = $self.children();

If statement fails with $(this), but works with absolute

I ran into this very odd scenario.
This won't hide the H1:
if ($('#content h1').hasClass('active')) {
$(this).hide();
}
Only this will:
if ($('#content h1').hasClass('active')) {
$('#content h1').hide();
}
Why can't I use the (this)? Is something wrong with the script?
That is the correct behaviour. In the context of your if statement this does not hold a reference to your h1 element but to the document element (or function if you are inside of a function).
You could do:
$('#content h1').foreach(function() {
if (!$(this).hasClass('active')) {
$(this).hide();
}
});
In this case, as Jan explained, this will be in the context you expect it to be (the heading element).
What you want is probably
var h1 = $('#content h1')
if (h1).hasClass('active')) {
h1.hide();
}
your "this" will, as stated above, not reference your object.
The statement $('#content h1').hasClass('active') returns a Boolean value (true or false), as opposed to a jQuery object, which is what you're trying to use $(this) for. See the usage of hasClass here.
If you're trying to perform an action on all elements that match a certain selector, give this selector a try instead:
$("#content h1.active").hide();
This finds all elements with an id attribute of "content" that contain an h1 element with a class attribute of "active," and hides them all.

Categories

Resources