JQUery find and match parent based on a dynamic child class - javascript

Ok it's a little hard to explain in a single title but basically I have a dynamic class added to a child element based on it's parent's dynamic class. Added so:
$('ul').each(function(key){
if ($(this).hasClass('sortable')){
$(this).addClass('parent' + key);
$(this).children().addClass('parent' + key);
};
});
The structure is pretty simple after this:
<ul class="parent0">
<li class="parent0">
<ul class="parent1">
<li class="parent1"></li>
</ul>
</li>
</ul>
Now the UI has the user move these li outside of the parent and placed elsewhere. Later on, I want to check the element and then match it to it's corresponding (original) parent. It can't be $(this) parent because it will be moved out of the parent but the classes still remain.
So the check is looking for .parent(n) and then finding the ul with .parent(n) eventually this code will live inside:
$('sortable li').appendTo($('THIS-IS-THE-DYNAMIC-CLASS'));
So I'm assuming the find will be before this but I don't know how to write that.

I would use a different attribute other than class so it can be wholly unique. Either use $(this).data or $(this).attr. And I would recommend assigning IDs to the parent (or a different attribute) that, again, can be wholly unique. This will keep things cleaner in my opinion.
For example...
Assuming:
$(this).attr('parentClass', '.parent' + key);
then
$('.sortable li').each(function() { $(this).appendTo($(this).attr('parentClass')); });

Related

How can I change an attribute value for all list items?

I have a simple structure like:
HTML
<ul id="costsDropdown">
<li data-position="bla bla"></li>
</ul>
and I want to change each "data-position" attribute of my list Elements.
My first Jquery Shot was this here:
$("#costsDropdown ul").each(function() {
$("li").attr("data-position", "TEST-VALUE123");
});
but it doesnt work, I think my selector are wrong...
could anyone give me a hint please?
Thanks for any help!
Greetz
Your selectors are a bit off
$("#costsDropdown ul").each
That is trying to select the child ul of the container #costsDropdown (which is the ID of the ul) - what you want is:
$("#costsDropdown li").each(function() {
$(this).attr("data-position", "TEST-VALUE123");
});
ID's are unique - no need to double up the selector with an ID and the type of element it is.
Note that I used $(this), not $("li"), inside the each callback. $("li") selects all li elements, anywhere on the page; we just want a jQuery wrapper for the one specific one we're handling inside the each.
In fact, the each is completely unnecessary because of the set-based nature of jQuery; if you use the .attr setter, it sets the attribute on all elements in the set:
$("#costsDropdown li").attr("data-position", "TEST-VALUE123");
That will set the value on all of the li elements inside #costsDropdown.
If you need to set separate individual values on the individual li elements, you still don't need each (though it's fine if you want to use it); you can use the version of attr that accepts a callback that it uses to find out what value to set:
$("#costsDropdown li").attr("data-position", function(index) {
return "Test value " + index;
});
That will set "Test value 0" on the first li, "Test value 1" on the second, etc. And like the each example above, if you need to, you can use this within the callback to refer to the li for that call (possibly using $(this) to wrap it if you need a jQuery wrapper).
$("#costsDropdown ul") matches no elements, it has to be $("#costsDropdown") (#costsDropdown is the ul).
And even that is unnecessary. Go
$("li[data-position]").attr("data-position", "TEST-VALUE123");
instead.

Is there a way to reach parent's sibling in jquery?

I have a button inside a div. When clicked, i will need to grab the length of a list that is a sibling to the parent container. maybe so even a grandparent container.
The gist of the code looks something like this below. (My actual code is actually nested deeper than this example. I would like to know how to target part a sibling of a parent or grandparents or even great great grandparent...)
HTML
<div>
<div class="button-parent">
<div class="button-containers">
<button>Click Here!</button>
</div>
</div>
<div class="list-container">
<ul class="lists">
<li>bar</li>
<li>bar</li>
<li>bar</li>
<li>bar</li>
<li>bar</li>
</ul>
</div>
</div>
jquery
$('button').parent('button-parent')
.closest('list-containers').length
.closest() finds the closest ancestor (parent), so it won't find your .list-container.
You can do this a few ways though...
Give your surrounding div a class and use .find() to locate your list if it is the only list in your parent div:
$('button').closest('.parent-div').find('.list-container');
Use next() if .list-container will always be the next item after .button-parent:
$('button').closest('.button-parent').next('.list-container');
You can use .siblings() if .list-container will always be on the same DOM level as .button-parent:
$('button').closest('.button-parent').siblings('.list-container');
From there you can fulfil the rest of your requirement to capture the length of the list by selecting all the li elements and counting them. If we use number 1 above as an example, it might look something like this:
const list = $('button').closest('.parent-div').find('.lists');
const items = list.children();
const count = items.length;
NOTE: The selection for list in this example targets ul.lists rather than .list-container, as this allows us to count using children(), which is much less intensive than find().
I suppose you can use Use parents([selector]) or closest([selector]) with siblings([selector])
parents() looks for ancestors, closest() be used as well if you want to select only the first going upward in the ancestry
siblings() select for siblings
you can pass them selectors or use eq()
one more things your jquery snippet doesn't seem to include . for class selector
Three methods that I tried and worked are
$('button').parents().eq(1).siblings('.list-container');
$('button').parents('.button-parent').siblings('.list-container');
$('button').closest('.button-parent').siblings('.list-container'));
Check out this jsfiddle, i have selected list-container using the three methods

How to check if class attribute exist?

I'm trying to check if there is no class tag within a <li> </li> tag.
For example, if I have this:
<li class="menu...."> words </li>
I want to ignore it. However if I have this:
<li> words </li>
I want to use it.
What I currently have is something along the lines of:
$("li").each(function() {
if ($(this).classList.contains('') {
do function
}
})
However, this is not working - how would I go about doing this?
Thanks in advance
$('li:not([class])');
This will select all li elements without a class at all. You can replace [class] with a specific class as well, or use hasClass.
You can do this:
$("li:not(.menu)").whatever();
That's not the fastest way necessarily; it may be faster to do this:
$("li").filter(function() { return !$(this).hasClass("menu"); }).whatever()
edit if you want to operate on <li> elements that have no class, then just check the .className property:
$("li").filter(function() { return !$(this).prop("className"); }).whatever()
However, I would suggest that that's not a good coding pattern. It's fragile because it relies on any future changes to your page for purposes completely unrelated to what you're doing now not involving the addition of a class. You'd be better off explicitly checking for specific classes that you're not interested in.
Like, maybe 3 months from now, somebody decides that all the list items that are about penguins be made black and white. You then add the class "penguin" to all those <li> elements. If you don't remember this change you're making now, all of a sudden that functionality will be broken.
You can use prop()
$("li").each(function() {
if (!$(this).prop("class")) {
doFunction();
}
});
DEMO
The classList is only available on Element instances, not on the jQuery object.
$("li").each(function() {
if (this.classList.length === 0) {
do function
}
})

Remove class from element and add to next element

I have a list of links, one has the class active.
On my next button click id like to remove the class from the current element and add it to the next only I cant seem to get it to add?
Ive made a fiddle to hopefully explain my problem, any help would be great, thanks
http://jsfiddle.net/h6D4k/
$('.next').click(function(){
$('ul.pagination').find('a.active').removeClass('active');
$('ul.pagination').find('a.active').next('a').addClass('active');
return false;
});
One of the jQuery most usable conveniencies is that its methods are (usually) chainable - in other words, they return the very object they are called from. So you can simply write this:
$('ul.pagination').find('a.active').removeClass('active').closest('li')
.next('li').find('a').addClass('active');
... as it's <li> elements that should be 'nexted', not <a> ones. But in fact, you shouldn't probably discard 'active' altogether if it's the last element in question:
var $a = $('ul.pagination').find('a.active'),
$li = $a.closest('li'),
$nextLi = $li.next('li');
if ($nextLi.length) {
$a.removeClass('active');
$nextLi.find('a').addClass('active');
}
This is actually what you want based on your html structure in you fiddle. http://jsfiddle.net/h6D4k/1/
$('ul.pagination').find('a.active').removeClass('active').parent()
.next().find('a').addClass('active');
Because once you've done this...
$('ul.pagination').find('a.active').removeClass('active');
There is no more a.active - the active classname has been removed from that element. So repeating the same selector...
$('ul.pagination').find('a.active')//...
... will select nothing.
Chain it all together instead.
$('ul.pagination').find('a.active').removeClass('active').next('a').addClass('active');
You have a second problem. According to the jQuery API for next(), it will:
Get the immediately following sibling of each element in the set of matched elements. If a selector is provided, it retrieves the next sibling only if it matches that selector.
You're not trying to get the following sibling:
<ul class="pagination">
<li><a class="one active" href="#">X</a></li>
<li><a class="two" href="#">X</a></li>
<li><a class="three" href="#">X</a></li>
</ul>
Next
Prev
You're trying to get the next <a> in the whole document. That's more challenging - and I'm not sure how to do it.
I would write it this way, preventing the action from doing anything on the last li as well.
http://jsfiddle.net/h6D4k/6/
$('.next').click(function(e){
e.preventDefault();
if ($("ul.pagination a.active").parent().is(":last-child")) return;
$('ul.pagination a.active').removeClass('active').parent().next().find("a").addClass('active');
});
You have two errors in your code:
Once removed, the active class can't be found anymore
your a tags are nested in li tags so next() doesn't work as you expect
To simplify things, you could attach the active class to the li tags.
Live demo: http://jsfiddle.net/h6D4k/7/
Code:
$('.next').click(function(){
$('ul.pagination').find('li.active').removeClass('active')
.next().addClass('active');
return false;
});

jQuery: take existing HTML, modify one node, then reinject

I have a blob of HTML that I'm retrieving using simple jQuery selectors, something like the following:
<div id="stuff">
<ul>
<li>some</li>
<li class="ninja">stuff</li>
</ul>
</div>
I'm basically doing:
var myblock = $("#stuff").html();
now I want to inject an additional li element to the bottom of that li list with very similar attributes to the li above it, but i want to change the class ninja to class samurai.
What's the best way of going about that with jQuery?
Simply select the <ul> and append the <li> to it
$("#stuff ul").append('<li class="samurai">stuff</li>');
If you actually wanted to copy the last <li> element, change the class then add to the list, then you could do something like this
var ul = $("#stuff ul");
ul.append(ul.find('li:last').clone().removeClass().addClass("samurai"));
pass true into clone() if you also want to copy event handlers too.
The problem with taking a whole chunk of HTML, changing an element and then reinserting is that any event handlers set up on elements that will be replaced when you reinsert the HTML will be lost, so it's more elegant/ and less cumbersome/intrusive to simply manipulate the part of the DOM that you need to.

Categories

Resources