Which FOR loop is the best way to traverse through elements? - javascript

Which is the best way to traverse through a <ul> list and add a particual text to each <li> ??? Can i do with with a FOR loop like:
for (i=0; i<$('li').length; i++){
('li').eq(i).text(bla bla)
}

You can simply use text() with callback it will iterate
$('li').text(function(i,v){
// i - index of the element and v - old value
return 'bla bla';
// -------^---- new value to update
});
For example :
var con = ["first", "second", "third", "fourth"];
$('li').text(function(i) {
return con[i];
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>

In your example you dont need any loop whatsoever
$('li').text('blah blah')
will already update every li with the text

Yes it is. While each() has a simple syntax it is worse performance wise. Nevertheless you should select a DOM object one single time and then use the reference if nothing has changed withing the DOM. Otherwise jQuery will search the DOM multiply times every single loop
var elements = $('li');
for (var i = 0; i < elements.length; i++){
elements.eq(i).text(bla bla)
}

Nope, this is too heavy. Bare in mind that every time you call $('li'), jQuery looks for all <li> elements in the page and generates a collection out of them. As such, jQuery has a wonderful feature of method chaining and iterating, that will help to keep code fast. For iterating elements in a collection you can use a special .each method:
$('li').each(function(i) {
$(this).text('element #' + i);
});
Or if you simply need to set the same text to all matching elements in a collection, use .text method applied to a selected jQuery object:
$('li').text('same text');

Related

Get the Count of Element in JS which has the specified Value (Without JQUERY)

I have an requirement in JS where, i want to get the count of li element which has the same inner value. What is the best way to do it ? I know we can achieve this in Jquery easily using find and contains but i don't want to use jquery.
I want the length of li elements has the Same Value.
For Eg: Say i want to find out how many LI has the value 'A'.
Below is the JS i have tried, which i think is not the best cos if i have say around 10,000 LI then i will have to loop through all the elements get their values and check if its what i want or no, which will surely hit the performance.
Note : LI element is added runtime with their Value.
HTML
<ul class="s_1" id="ULE">
<li class="r1">A</li>
<li class="r1">A</li>
<li class="r1">B</li>
<li class="r1">A</li>
</ul>
JS
var LI = document.getElementsByClassName('r1');
var cnt = 0;
for(var i=0;i<LI.length;i+=1){
if(LI[i].innerHTML == 'A'){
cnt += 1;
}
}
if(cnt === 4)
alert('working good!!');
JS Fiddle
I don't think there is a better way to improve the performance. If you have nothing but the DOM to work with (e.g. if the data is from user input), and not the underlying data structure from which you created the data, AFAICT there is no other structure to collect all of the elements than into an array-type structure, which will then require O(n) time to check every element.
Rather than have a count target, which is therefore dependent on the amount of list elements, try instead a function to handle the data, which increases the convenience somewhat:
function isEveryElementEqual(nodeList) {
val = nodeList[0].innerHTML;
for (var i=1; i<nodeList.length; i++) {
if (nodeList[i].innerHTML !== val) return false;
}
return true;
}
var LI = document.getElementsByClassName('r1');
console.log(isEveryElementEqual(LI)); // Returns false with the above HTML
You don't have to search all <li> in the document. getElementsByClassName can be applied to an element, it will then only search within that element. So you can do:
var LI = document.getElementById('ULE').getElementsByClassName('r1');
DEMO
You can also simplify this with querySelectorAll:
var LI = docuement.querySelectorAll('#ULE .r1');

Get Element in HTML Ordered List by Index Using Javascript

I looked quite a bit for a solution for this but I surprisingly couldn't find anything. Maybe I just didn't search for the right words. I found a bunch of questions about getting the index by the element, but I need the opposite.
I'm trying to use javascript and jquery get an element in an ordered list by it's index in the list. For example, if I have this list:
<ol>
<li>Zero</li>
<li>One</li>
<li>Two</li>
<li>Three</li>
</ol>
I would like to be able to get the first one (Zero) by its index of 0, or the second one (One) by its index of 1.
So far I have tried a few things:
A simple function based off of the getting the index of an object in a list using the id.
elem = list.index(0); //To get the first element, but this is not a thing.
A loop like this:
//elem is the element I am currently at.
//Starting at the last element and going to the first.
var elem = list.getLastChild(); //But list.getLastChild() is apparently
//not a thing although it is here ([w3c link][1]).
//Start at 0 and go to the index
//(may/may not need the = before num, but I think I do)
for(var i=0; i<=num; i++){
//Set elem to it's previous sibling
elem = elem.getPreviousSibling(); //getPreviousSibling is probably not a thing as
//well but I couldn't get that far before it broke anyway.
}
//Return the element at the index
return elem;
So is there a way to do this?
Thanks.
There are many ways to do this. You can use :eq selector. Something like this?
var $lis = $('ol li');
for(var i=0; i < $lis.length; i++)
{
alert($('ol li:eq(' + i + ')').text());
}
Demo
So, as this is zero indexed. You could do: $('ol li:eq(0)') for getting the first element.
You can also use css, nth-child, nth-of-type selector:
alert($('ol li:nth-child(1)').text()); // This starts with 1 index, non-zero indexed.
You can use JQuery:
$("ol li:nth-child(1)")
$("ol li:nth-child(n)")
http://api.jquery.com/nth-child-selector/

Remove first child in javascript

I'm trying to remove the first li in an ol using the DOM removeChild(). But for some reason it doesn't work.
This is my javascript:
document.getElementById('queue').removeChild(
document.getElementById('queue').childNodes[0]
);
And this is my HTML:
<ol id="queue">
<li>Surprised Kitty (Original)<span class="nodisplay">0Bmhjf0rKe8</span></li></ol>
I tried alerting the childNodes[0], and it returns [Object Text], which seems a bit weird, when I was expecting just the object.
Hope I've been clear.
Try this one-liner:
document.getElementById('queue').removeChild(document.getElementById('queue').getElementsByTagName('li')[0]);
With expanded explanation:
var queue = document.getElementById('queue'); // Get the list whose id is queue.
var elements = queue.getElementsByTagName('li'); // Get HTMLCollection of elements with the li tag name.
queue.removeChild(elements[0]); // Remove the child from queue that is the first li element.
Between the <ol id="queue"> and the <li> tag are spaces and a line break. These make up a text node. The first child of the #queue element is therefore a text node.
You can use the .children property instead of .childNodes, it only considers element nodes, or iterate over all child nodes until you find the first li node, like suggested by dystroy.
remove all lists contained by queue:
var list=document.getElementById('queue');
list.removeChild(list.getElementsByTagName('li')[0]);
Child nodes aren't just the elements you think about but also the text nodes. You can iterate over the nodes and remove the first LI.
var p = document.getElementById('queue');
for (var i=0; i<p.childNodes.length; i++) {
if (p.childNodes[i].tagName=='LI') {
p.removeChild(p.childNodes[i]);
break;
}
}
Demonstration
Note that this is more an explanation than the most practical solution. Javascript has other iteration solutions for you, among them getElementsByTagName, so you may do this :
var p = document.getElementById('queue');
p.removeChild(p.getElementsByTagName('li')[0]);
Demonstration
You can use this single line of code. Which will delete always first child element of the parent.
JavaScript:
document.querySelector('#queue').firstElementChild.remove();
HTML:
<ol id="queue">
<li>
Surprised Kitty (Original)
<span class="nodisplay">0Bmhjf0rKe8</span>
</li>
</ol>

Selecting a last child in javascript

I have a handle on an Un-ordered List (for my example i will call the handle Var1) and would like to be able to assign its last li to a variable. I tried Lastli = var1.lastChild the only method I figured would work but it didn't. I can't seem to find a answer to this using only Javascript not jQuery any help is appreciated.
You can select the parent element and use the lastChild property.
var container = document.getElementsByTagName("ul")[0];
var lastchild = container.lastChild;
Or you select all the items into an array and get the last item. Here is a quick example:
var items = document.querySelectorAll("li");
var lastchild = items[items.length-1];
you can select all 'li' and take the last one. Something like:
var myLi = document.getElementsByTagName('li');
var lastLi = myLi[myLi.length-1];
Lets consider an example
<ul >
<li>Coffee</li>
<li>Tea</li>
<li>Milk</li>
</ul>
To get the last child of the list you can simply make use of queryselector
document.querySelector('li:last-child'); //this will return Milk which is the last child of the list
document.querySelector('li:first-child') OR document.querySelector('li'); //both will give you the first child of the list
Suppose you want the n-th child for that you can use the following syntax:
document.querySelector('li:nth-child(2)'); //it will return the second child (here Tea)
If you want all the list item in the given list:
document.getElementsByTagName('li') //(Will return the whole list)here i am using tagname. It can be also applied on classname or element id
Try this: .childNodes[childNodes.length - 1]
either ulReference.children[ulReference.children.length -1] or ulReference.childNodes[ulReference.childNodes.length -1]. The difference between the two can be found here
The simplest way is to use the document.querySelector and use the :last-child to get it.
Exemple:
const list = document.querySelector("li:last-child");

jquery find() method

Please consider the following code :
<!DOCTYPE html>
<html>
<style>
p{ width:200px; }
</style>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
<p><span>Hello</span>, how are you?</p>
<p>Me? I'm <span>good</span>.</p>
<script>
$(document).ready(function(){$("p").find($("*")).andSelf().css("background- color","blue"); });
</script>
</body>
</html>
The output is the whole document turning into blue color while I only wanted the paragraph and span inside it to turn blue.
If I use $("p").find(" * ") instead of $("p").find($(" * ")) then everything shows according to my need. Can anyone work out the difference between the two approach?Thanks!
Note: Please everyone note that I know there are easier methods to do this stuff,but I just want to know why this didn't work..
Disclaimer: The other answers already suggest better selectors to
achieve your goal, but I understand you want to know why andSelf()
ends up matching all the elements in the document, so I'll try to
explain that.
First, as you know, andSelf() adds the previous set of elements on the stack to the current set. So, in your case, it seems it should add the <p> elements to the set containing their descendants:
$("p") // match the paragraphs
.find($("*")) // match all the elements that descend from a paragraph
.andSelf() // add the paragraphs to the elements above
However, the above assumes that find($("*")) is the previous set of elements, and that's simply not the case here. The first hint about this comes from the documentation for find():
As of jQuery 1.6, we can also filter the selection with a given jQuery
collection or element. With the same nested list as above, if we start
with:
var $allListElements = $('li');
And then pass this jQuery object to find:
$('li.item-ii').find( $allListElements );
This will return a jQuery collection which contains only the list
elements that are descendants of item II.
The last sentence is particularly interesting: it seems to imply that the jQuery object passed to find() is filtered in order to match the descendants of the elements in the original set. If that's indeed the case, the logic would be inverted, and the previous element set would end up being $allListElements instead of the set returned by find().
A look at the jQuery source code shows that's exactly what happens:
find: function(selector) {
var self = this, i, l;
if (typeof selector !== "string") {
return jQuery(selector).filter(function() {
for (i = 0, l = self.length; i < l; i++) {
if (jQuery.contains(self[i], this)) {
return true;
}
}
});
}
// [...]
}
So, when you write:
var elements = $("p").find($("*")).andSelf();
You're actually writing the equivalent of:
var self = $("p"), i, l;
var elements = $("*").filter(function() {
for (i = 0, l = self.length; i < l; i++) {
if ($.contains(self[i], this)) {
return true;
}
}
}).andSelf();
As you can see, the previous element set is actually $("*") instead of the set returned by find($("*")) because of the logic inversion. Therefore, all the elements in the document end up being legitimately added to the current set by andSelf().
You just need
$("p").css("background-color","blue");
To change the color or all the p tags in the document. Is there some specific reason for the way you have done it?
The $("*") has no context, so it selects every element in the document. You want to find all elements within the currently selected element, so you need to just pass the string to find.
However, it's completely unnecessary and you could just apply the style to the p (as the span is a child you don't to apply it to that too):
$("p").css("background-color","blue");
Note that in that line above I've used background-color with no spaces, unlike in your question. I'm guessing it was just a typo when you wrote the question, but it won't work if you put spaces in the property name.
You don't have to do any of that. Just do this.
$(function() { $("p").css('background-color', 'blue'); });
Note: $(function() {}); is the same as $(document).ready(function(){});
Edit: Since you have two, you may have to do this:
$(function() { $("p").each(item, function() { item.css('backround-color', 'blue'); })});
Edit2: Based on your comments, you want this:
$(function() { $("p").find('span').andSelf().css('background-color', 'blue'); });
The difference between $("p").find(" * ") and $("p").find($(" * ")) is that in the second one you're passing find() a jquery object instead of a regular selector string.
EDIT: I just tried it out. Looks like adding the andSelf() makes it select the entire document somehow. The logical process would be select p > find all elems inside that match everything in the document > select self(p) > color, but it seems to be going wrong at the select self bit.
I think it(the andSelf()) just selects the object passed to find(), which is $('*'), and so selects everything.
If you want to select all P's simply use
$(document).ready(function(){
$("p").css("background-color","blue");
});
No reason to complicate stuff
If you want to select the spans inside you can do something like
$(document).ready(function(){
$("p > span").css("background-color","blue");
});
** Update **
Your selector attribute in your find query is bad, you shouldn't have it like $("*") but only "*". However the $("p").find("*")... will only select any elements inside the <p> tag so trailing the find method with an andSelf will make the selection ambiguous.

Categories

Resources