Filter method jQuery - javascript

Please help me out with the following code. I don't understand it. I have to use a snippet like this in my project.
$('strong', this) <- this part is not clear to me at all.
Please be kind enough to explain the whole code line by line if possible.
<ul>
<li><strong>list</strong> item 1 -
one strong tag
</li>
<li><strong>list</strong> item <strong>2</strong> -
two <span>strong tags</span>
</li>
<li>list item 3</li>
<li>list item 4</li>
<li>list item 5</li>
<li>list item 6</li>
</ul>
JavaScript:
$('li').filter(function(index) {
return $('strong', this).length == 1;
}).css('background-color', 'red');

$('strong', this) is jQuery selector with $(target, context) format.
According to your code:
this refers to li and $('strong', li) is searching a <strong> that within that li tag.
This statement can also be written as:
$(this).find('strong') and from jQuery library code you'll see that:
$(target, context) format internally implement the
$(context).find(target) process.
For more see here.

The code is basically getting a list of li elements using the jQuery $('li') (this will get all <li> ... </li> tags on the page)
It then reduces this set with the .filter function, filter takes a function as an argument, the function is called on each element in the list, if it returns true the element is returned in the list from filter if it return false the item is ignored.
In this context the function calls $('strong', this).length == 1 where this is the li tag that currently being decided checked by the filter, as mentioned in other answers it's simply checking returning the list of <strong>..</strong> tags in the current li. If there is not strong in the current li, length is 0 so the function returns false, this means the filter wont return that element in the list it produces, it then moves on to the next li.
this means the the first part of the code simply produces a list of li's with a strong tag in them, this is then chained with the css function which colours all those tags in red.
Hope that helps.

Related

Parallel sorting two different lists using jquery sortable

I am having very specific case where I needed to split the data into two different lists in html. Like this:
<ul id="first_list">
<li ref="1">The quick brown</li>
<li ref="2">My father works</li>
</ul>
And the second list is like:
<ul id="second_list">
<li ref="1">jumps over the lazy dog</li>
<li ref="2">at the Ministry of Defense</li>
</ul>
So as you can see I from the "ref" attribute I know which <li> element from the second list is a continuation of which <li> element from the fist list.
Now I need to enable the jQuery UI sortable() to those lists but when I reorder the first I need the second reordered too. I tried using handle but it doesn't works because it looks like the handle element needs to be inside the element which is moved but these two are at a different places in the page.
I do believe that you should have shared some of your code (what you've tried), and I'm assuming you are familiar with Sortable plugin that you are using. You should run the below code on success event of Sortable so as soon as you sort any LI, the other list will be sorted too. Anyways,
Try this:
//This line stored the LIs in a temp variable and remove it
var $cachedList = $('<div />').html($('#second_list').html());
$('#second_list > li').remove();
//This line loads up the first UL's LIs and replaces the content for each LI
//using $cachedList.
$('#second_list').html($('#first_list').html()).find('li').each(function () {
$(this).html($cachedList.find('li[ref="'+$(this).attr('ref')+'"]').html());
});
Demo: http://jsfiddle.net/AR8px/

How would I prevent JQuery from selecting more than 1 level of children dom elements?

How would I only select Item A and Item B pragmatically while excluding the sub item?
<div id="nav">
<ul>
<li>
<p>Item A</p>
<ul>
<li>
<p>Sub Item A</p>
</li>
</ul>
</li>
<li>Item B</li>
</ul>
</div>
Well after a quick test run - this is my contribution to this issue
$("#nav p:first, #nav > ul > li:eq(1)");
You specified that you wanted only those two items and no sub items so this is what jQuery will capture :
[<p>​Item A​</p>​, <li>​Item B​</li>​]
You can easily separate selectors by placing a comma between them.
Now that you have seen my solution I would strongly suggest that you take Xenon06's advice...
Giving your markup classes really helps you to keep track of them. Especially with jQuery. The class attribute while IMO mostly used for styling is a perfectly valid selector to use and abuse in your jQuery code. That is of course if you actually have access to that HTML. If you don't kindly ignore my last paragraph :)
This will select any first level li's that have only text and no children and any children of a li that isnt a ul. Given this is not a good way to do it. You should really put classes on your stuff to start with. But if that's not an option this will get you there.
$($('#nav').children()).children().each(function(){
if($(this).text() !== "" && $(this).children().length === 0 ){
$(this).addClass("IwantThisElement");
}
});
$($($('#nav') .children()) .children()) .children(':not(ul)').each(function(){
if($(this).text() !== ""){
$(this).addClass("IwantThisElement");
}
});
$('.IwantThisElement').text('Assuming Control');
Well, if your structure was more consistent, you could use direct children selectors, ie:
$("#nav ul li > p")
However your Item B is not in a paragraph. Without defining more what you want, you'll need to put classes on the items you want and do
$("#nav .yourclass")

Getting an element in Javascript - but what element # is it within the document?

I've got a set of elements that, on click, I want to change colour. Now, I have a colour assigned to each of them (ie, if it's the first one in the list then this colour, if it's the second then a different colour...) but how do I check which one they are? Like, if I click on the third, how do I know it was the third? Is there a javascript method for it or even a jQuery method?
Thanks
If they're siblings:
$(this).index();
This returns a 0-based index, so the third is 2.
If they're not siblings, cache the set:
var els = $('.my_group_of_elements');
Then do this:
els.index( this );
jQuery has an .index() method, that should do what you want.
Example: http://jsfiddle.net/au2fQ/
HTML
<ul id="Test">
<li>Click Me</li>
<li>Click Me</li>
</ul>
<ul id="Test2">
<li>Click Me 2</li>
<li>Click Me 2</li>
</ul>
JS
$('li', '#Test,#Test2').click(function(){
var i = $(this).index(),
k = $(this).index('li');
alert('This is li '+i+' in the ul. This is li '+k+' in the page.');
});

Jquery child selector vs. .each

Given the following example table:
<ul class="topnav">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
What are the differences between:
$selector1 = $('ul.topnav > li');
and
$selector2 = $('ul.topnav').each();
EDIT:
$selector2 = $('ul.topnav li').each();
The first will contain all li's which are a direct child of ul.topnav, the second will contain all ul.topnav elements.

			
				
$('ul.topnav > li') will select all <li>s directly under the ul.
each should take a function as a parameter, and iterate over all matched <ul> - it doesn't not take the children <li>s. If anything, you want $('ul.topnav').children(), which is identical if the ul only contains li elements anyway.
For example, this will alert the number of children each list has (in your case, only the number 3)
$selector2 = $('ul.topnav').each(function(){
alert($(this).children().length);
});
Also see the jquery API.
The second one will evaluate them individually, whereas the first one will evaluate them as a group

Jquery recursive function combine nested li into one

I am trying to convert a nested li into one single li using recursive method using jquery
html as follows
<ul>
<li>item-1
<ul>
<li>item-1.1</li>
</ul>
</li>
<li>item-2
<ul>
<li>item-2.1</li>
<li>item-2.2
<ul>
<li>item-2.2.1</li>
<li>item-2.2.2</li>
</ul>
</li>
</ul>
</li>
<li>item-3
<ul>
<li>item-3.1</li>
</ul>
</li>
<li>item-4</li>
<li>item-5</li>
</ul>
Final single li as below
<ul>
<li>item-1</li>
<li>item-2</li>
<li>item-3</li>
<li>item-4</li>
<li>item-5</li>
<li>item-1.1</li>
<li>item-2.1</li>
<li>item-2.2</li>
<li>item-3.1</li>
<li>item-2.2.1</li>
<li>item-2.2.2</li>
</ul>
basically loop through each level then append to the end of the list.
Any ideas how I can achieve this? so it can handle any level of the list item.
Here is a recursive approach that will give the output you're looking for:
function recurseFetchListItems($ul)
{
var $li = $ul.remove().children("li").remove();
if ($li.length) {
$li = $li.add(recurseFetchListItems($li.children("ul")));
}
return $li;
}
It uses add() to accumulate the different levels of list items, while removing each level from the document. It also uses children() instead of find() in order to process a single depth level per call.
From there, you only have to start from the first <ul> element, add the cumulated set of list items back to the document, and wrap them in a new <ul> element:
$(document).ready(function() {
recurseFetchListItems($("ul:first")).appendTo("body").wrapAll("<ul>");
});
You can see the results in this fiddle.
Original (misguided) answer follows:
You don't really need a recursive function to do that, because whole DOM element trees can be matched with a single selector. For instance, $("li") matches all the list items, whatever their depth is.
So, to achieve what you want, we only need to match all the <li> elements, remove their parent <ul> elements from the document, then wrap the list items into a new <ul> element using wrapAll() and add that element back:
$(document).ready(function() {
$("li").parent().remove().end().appendTo("body").wrapAll("<ul>");
});
You can see the results in this fiddle.

Categories