Is there a way to allow me to iterate through an ordered list similar in functionality as table.rows? I am using Javascript.
The reason I ask this is because I have an ordered list that contains another ordered list inside. I just want to return the parent list items and not the child.
<ol id="pList">
<li>Item A</li>
<li>
<ol id="cList">
<li>A's Child 1</li>
<li>A's Child 2</li>
</ol>
</li>
<li>Item B</li>
<li>Item C</li>
<li>Item D</li>
</ol>
I now use getElementsbyTag and that returns all li's including the one in cList. I just want the ones in pList.
Thanks
FYI: I would prefer it done in Javascript. The code has to work within Greasemonkey. I don't really know much about jquery and I am not really much of a javascript programmer.
There is no specific property that gives you direct access to the <li> children of an <ol>.
However it is very easy to enumerate them, particularly when you consider that the only legal children of an <ol> must be white space text nodes and <li> nodes.
var ol = document.getElementById('pList');
var li = [];
var node = ol.firstChild;
while (node) {
if (node.tagType === 3 && node.tagName === 'LI') {
li.push(node);
}
node = node.nextSibling;
}
At the end of which, the array li contains the required children.
The above code will work in any browser. The .children collection has problems on older versions of MSIE, and querySelectorAll is even more modern (and therefore less widely supported).
If using querySelectorAll()* is an option for you, it's easy:
var listItems = document.querySelectorAll( '#pList > li' );
* note: it's a native DOM method, and has nothing to do with jQuery
There's a table of immediate children in every javascript object :
document.getElementById('pList').children
You can even iterate through it and check whatever your need :
var el = document.getElementById('pList');
for (var i = 0; i < el.children.length; i++) {
if (el.children[i].tagName == "LI") {
el.children[i].doWhatever();
}
}
Related
This is the first time I’ve thought about moving my events outside of the normal HTML onClick=”” event but I cant seem to find any references as to how I would do this with a li list.
Basically I’m trying to get the number associated with the scrollToArtical(#) in to myElement.onclick. How would you rewrite this so that the event is in the .js file.
I’ve tried variations of to get at the element but these don’t work:
var objScrollToNav = document.getElementById("id_ScrollToNav").children;
var objScrollToNav = document.querySelector("#id_ScrollToNav a");
Any help would be greatly appreciated – CES
My old code is:
<ul id="id_ScrollToNav" role="list">
<li class="sectionNavOff"><a onclick="scrollToArticle(0)" role="link">•</a></li>
<li class="sectionNavOn"><a onclick="scrollToArticle(1)" role="link">•</a></li>
<li class="sectionNavOff"><a onclick="scrollToArticle(2)" role="link">•</a></li>
</ul>
Use document.querySelectorAll to get an array-like list, then loop over them. To keep a reference to the index, make sure you also pass the index into a new closure (the addEvent function below creates a new closure).
function scrollToArticle(index) { console.log("Scrolling to:", index); }
// Select all the elements.
var links = document.querySelectorAll("#id_ScrollToNav a");
// This function adds event listener, and holds a reference to the index.
function addEvent(el, index) {
el.addEventListener("click", function() {
scrollToArticle(index);
});
}
// Loop over the elements.
for (var i = 0; i < links.length; i++) {
addEvent(links[i], i);
}
<ul id="id_ScrollToNav" role="list">
<li class="sectionNavOff"><a role="link">•</a></li>
<li class="sectionNavOn"><a role="link">•</a></li>
<li class="sectionNavOff"><a role="link">•</a></li>
</ul>
Since your li elements can be gathered up into an array and arrays have indexes, you really don't need to pass a hard-coded number to your function. You can just pass the index of the li that is being clicked to the function.
Also, don't use <a> elements when they are not directly navigating you anywhere. This can cause problems for people who use screen readers. Instead, set up the click event directly on the li elements and eliminate the a elements completely.
Lastly, don't use inline HTML event attributes (onclick). That is how we did event handlers 20 years ago and, unfortunately, this technique just won't die. There are many reasons not to use them. Instead, follow modern standards and separate your JavaScript from your HTML.
// Get all the li elements into an array
var items = Array.prototype.slice.call(document.querySelectorAll("#id_ScrollToNav > li"));
// Loop over the list items
items.forEach(function(item, index){
// Assign each item a click event handler that uses the index of the current item
item.addEventListener("click", function(){ scrollToArticle(index) });
});
// Just for testing
function scrollToArticle(articleNumber){
console.log(articleNumber);
}
#id_ScrollToNav > li {
cursor:pointer;
}
<ul id="id_ScrollToNav" role="list">
<li class="sectionNavOff" role="link">•</li>
<li class="sectionNavOn" role="link">•</li>
<li class="sectionNavOff" role="link">•</li>
</ul>
To add to the above, use data- attributes to separate css styles from javascript (meaning, html class tags should be used for html/css things only).
<li data-element="sectionNavOff">
<li data-element="sectionNavOn">
There are some minor downsides to using data- tags, mainly speed, but many enterprise applications and frameworks (e.g. Bootstrap) tend to believe the upside to separating styles from javascript completely outweighs the downsides. If I knew whether or not you use jQuery I could give you a detailed usage example.
We remove child of a certain html element through JQuery via:
$(PARENT_SELECTOR).children(CHILD_SELECTOR).remove()
But how can I make this behave like .splice() method (e.g. removing on the DOM tree the given index and offset). For instance:
Remove the last three children. Here I'll most probably use:
for(var x = 0; x < 3; x++) {
$(PARENT_SELECTOR).children().last().remove()
}
Remove 4th to 6th children. Here I'll use:
$(PARENT_SELECTOR).children().eq(3).remove()
$(PARENT_SELECTOR).children().eq(4).remove()
$(PARENT_SELECTOR).children().eq(5).remove()
Remove 5 elements starting from the 5th child ( this is the real scenario where I want to have a .splice()-like function for JQuery ):
var starting = 5,
index = 5
// I haven't tested this yet.
for(var x = index + starting; x > index; x--) {
$(PARENT_SELECTOR).children().eq(x - 1).remove()
}
And the list goes on... I can make my own case-to-case scripts for each scenarios [, that's easy]. I'm just wondering if JQuery has already it's own feature like this-- it will make my scripting shorter and will not make me to repeat writing similar codes.
I think $.slice is really what you are looking for. Below is the example:
<ul>
<li>list item 1</li>
<li>list item 2</li>
<li>list item 3</li>
<li>list item 4</li>
<li>list item 5</li>
</ul>
$( "li" ).slice( 2, 4 ).remove();
Just keep in mind that .slice() starts with index 0, so example above will remove the third to fifth child.
jQuery Slice method selects a subset of elements based on its index.
This method is used to limit the selection of elements in a group, by a start and end point: the start parameter is a starting index (starts at 0) from which to create the subset, and the stop parameter is an optional ending point.
You can find the better explanation here and here
$(document).ready(function(){
$("p").slice(1).css("background-color", "red");
$("p").slice(2,4).remove();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>para 0.</p>
<p>para 1.</p>
<p>para 2.</p>
<p>para 3.</p>
<p>para 4.</p>
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.
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
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.