can't iterate through a nodelist in chrome - javascript

I'm developing a chrome extension and having a problem with a nodelist type.
var compoentChange = document.getElementById("component_change");
var items = compoentChange.getElementsByTagName("option");
When I console.log(items), it shows [item: function]. When I expand it, it has all the option elements and length property.
The problem is that I can't access those elements. When I console.log(items.length), I get undefined.
How do I iterate through items variable?
for(i in items){} and for loop do not work.

NodeLists are array-like objects. You can iterate with regular for loop (not for..in):
for (var i = 0; i < items.length; i++) { ... }
Or you can convert this array-like object to a real array and use native array methods on it:
[].forEach.call(items, function(item) { ... });

You can still do items.length, so just make a for loop like this. I suggest pushing it into an array.
var myArray = [];
for(var i=0; i<items.length; i++){
myArray.push(items[i]);
}
Alright if this isn't an option maybe try something like this:
var myArray = [];
for(var i=0, e=1; i<e; i++ ){
if(items[i] != undefined){
e++;
myArray.push(items[i]);
}else{
break;
}
}

If you're logging the two during the pageload, the reason that you can console.log() the NodeList, but not the length attribute is because the NodeList is a "live" collection. Both are undefined until the DOM finishes loading, but because the NodeList is live, it will update in the Chrome console. The lengthattribute was undefined when it was logged, and because it's not live, it'll stay undefined in the console.
You can set a variable to reference the nodeList at any time, but wait until the DOM is ready before trying to use the data (using the document.ready function or perhaps document.addEventListener()).

I met similar problem with you. It turns out that it is because I should access data after DOM finishes loading.
document.addEventListener("DOMContentLoaded", function () {
divs = document.getElementsByTagName("div");
console.log(divs);
}, false);

for...of can be used for this situation. However due to a bug, this opportunity cannot be used on chromium.

Related

JS: What is the use of having a 'live' list with querySelector or getElementsByTagName vs. non-live querySelectorAll?

I understand that a live list allows the variable holding the nodes to be updated if another is added or removed but I'm struggling to think of an example of how this would be beneficial vs. using a non-live list (querySelectorAll)?
It allows you to write the variable assignment just once, rather than having to update it whenever you change the DOM. So you can do something like:
var allRows = document.getElementsByTagName("tr");
function processRows() {
for (var i = 0; i < allRows.length; i++) {
// do something with allRows[i]
}
}
Rather than:
function processRows() {
var allRows = document.getElementsByTagName("tr");
for (var i = 0; i < allRows.length; i++) {
// do something with allRows[i]
}
}
By itself this isn't very compelling, but if you have multiple functions that use allRows, you would need to repeat the assignment in each of them. The live NodeList allows them all to use the same list.
The implementation of live node lists uses a cache, so the list will only be recalculated the first time it's used after a DOM modification, so the cost of recalculating is amortized over all the functions.

Null style property on DOM element: JavaScript

I am trying to add some custom JavaScript to an Enjin web platform. In the platform's HTML, there is a common element in the forums that I want to change the background color of.
<div class="block-container">...content...</div>
I am attempting to access it with the following JavaScript code:
function onStart() {
for (block in document.getElementsByClassName("block-container")) {
console.log("block");
if (block.style != null) {
console.log("styleNotNull");
block.style.backgroundColor = "#252525";
}
}
}window.onload = onStart;
However, when the page loads, it logs the word "block" in the console for each element but does not change the color or log "styleNotNull". If I remove the null checker, it errors out and says that the style property is null. Most of the answers on this topic have been because the element was missing, but that is obviously not the case because the for loop is executing.
Pure javascript
Use ordinary for loop:
var blocks = document.getElementsByClassName("block-container");
for (var i = 0; i < blocks.length; i++) {
var block = blocks[i];
block.style.backgroundColor = "#252525";
}
Working jsfiddle.
Basically for..in loop iterates through the properties of an object passed. More info here.
JQuery
This could be easily done by jQuery. So just in case here is an example:
$(function() {
$(".block-container").css("background-color", "#252525");
});
Working jsfiddle.
In JavaScript, a for..in loop will loop through the object passed, but for each iteration, the iterator variable will be assigned the key of the current element, not the value. So, try this instead:
function onStart() {
var elements = document.getElementsByClassName("block-container");
for (key in elements) {
elements[key].style.backgroundColor = "#252525";
}
}
window.onload = onStart;
Edit:
For a discussion about whether to use for..in or a typical for loop for arrays in JavaScript, see Why is using "for...in" with array iteration a bad idea?
The for in loop is for enumerating properties but you want to iterate over an array. Use a for loop instead. Or Array.prototype.forEach if it's available to all the browsers you're targetting.
See this post for more info - Loop through an array in JavaScript

jQuery - text() method?

Being fairly new to jquery and javascript I can't seem to understand how the .text() method really works. I read through the jQuery documentation but still can't figure it out.
for (var i=0; i < arrayLength; i++){
var currentElement = $(".artist")[i];
var currentArtist = currentElement.text;
console.log(currentElement);
console.log(currentArtist);
}
currentArtist returns "undefined" in the console. It works fine on the $(".artist") alone, but not when I use the [i] or anything additional for that matter. What am I missing here? How else could I grab a text value inside a selector?
By using the [] operator on jQuery object you're accessing the raw element node that was found by jQuery. This raw element doesn't have the jQuery methods anymore, nor a text property.
If you want to get single element from jQuery object and keep the jQuery wrapper, use eq method.
var artistElement = $(".artist").eq(i);
artistElement.text(); // gets the text content of the element
The code you've posted is also not very optimized. For instance, with every loop iteration you're searching the document over and over again for elements with class artist. Better to cache that search result in a variable before performing the loop. And if the loop iterates over all .artist elements, you can use jQuery's each method.
$(".artist").each(function () {
var artist = $(this); // this poits to the raw element thus wrapping into jQuery object
console.log(artist.text());
});
var currentArtist = currentElement.text;
Should be:
var currentArtist = currentElement.text();
You should use a each():
$(".artist").each(function(i,val){
var currentArtist = $(val).text();
console.log(val);
console.log(currentArtist);
});
$(".artist") produce a jQuery object that could be like this:
[div, div, div, div, prevObject: jQuery.fn.jQuery.init, context: document, selector: ".artist"...]
So the result of $(".artist")[i] is a HTMLElement and do not have a text method, that's why you're getting undefined
Also text() is a function and may be followed with ()
But if you want to keep the for loop you can do
for (var i=0; i < arrayLength; i++){
var currentElement = $(".artist")[i];
var currentArtist = $(currentElement).text();
console.log(currentElement);
console.log(currentArtist);
}
.text() shows the text of an html element or set of html elements that would be visible to the user.

Retrieving links from webpage using javascript

I'm new to javascript and simply trying to pull links from a webpage so I'm doing the following:
for(link in document.links) {
console.log(link.getAttribute("href");
}
But if I do this:
document.links.item(0).getAttribute("href")
It returns the link for the first href
What am I doing wrong?
Here is the webpage I'm testing against: http://en.wikipedia.org/wiki/JavaScript_syntax
Just get the elements by tag name and avoid the for in loop.
var links = document.getElementsByTagName('a'),
i;
for(i = 0; i < links.length; i += 1){
console.log(links[i].getAttribute("href"));
}
Example Here
For your example, you would have used:
for(link in document.links) {
console.log(document.links[link].getAttribute("href"));
}
While that technically works, it returns prototype properties in addition to the link elements. This will throw errors since .getAttribute("href") won't work for all the return elements.
You could use the hasOwnProperty() method and check.. but still, i'd avoid the for in loop.
for (link in document.links) {
if (document.links.hasOwnProperty(link)) {
console.log(document.links[link]);
}
}
document.links.item
is an array of items.
document.links.item(0) gets the first item in that array.
document.links.item(1) gets the second item in that array.
To answer your question, what you are doing wrong is that you are not looping the links.item array as you did in your first example.
In your code, you are accessing item 0 and only getting the href from that. For that reason, you will only get one link.
What you probably want to do is get the href for all of the of the links at once
var hrefs = [], i
for (i=0;i<document.links.length;++i) {
hrefs.push(document.links.item(i).getAttribute('href'))
}
Then your hrefs array will contains all the urls

JQuery collection array suddenly becomes DOM HTMLDivElement

In my code I have a function that accepts an array of JQuery collections and applies some code to each via a for-loop.
The problem is that as soon as I reference one it somehow becomes a HTMLDivElement instead of a collection object.
function vacant_now($timetables, now){
console.log("1:" + $timetables);//still fine
for (var i=0; i < $timetables.length; i++){
console.log("2:" + $timetables[i]);//problem is here
var $timetable = $timetables[i];
console.log("3:" + $timetable);
$timetable.find(".booking").each(function(){ ...
it's called like this:
vacant_now($page.find(".timetable"), now);
I'm stumped.
The jQuery collection array is an array of DOM elements.
Doing this: $('#myDiv')[0];
returns the same as: document.getElementByID('myDiv');
Solution:
Use $('.timetable').eq(index);
for (var i=0; i < $timetables.length; i++){
$timetables.eq(i);
}
Cheers
Using [i] on a jQuery object returns the dom element. If you want the jQuery object at a specific index use the .eq() function:
console.log("2:" + $timetables.eq(i));
Example - http://jsfiddle.net/8FeEf/1/
With jQuery you can use the .each method, and after you must 'jquerify' the object :
function vacant_now($timetables, now) {
$timetables.each(function() {
var $timetable = $(this);
});
}
A jquery collection is in fact an array of DOM elements.
You can also use a for, the syntaxe is a little bit more verbose.
In all case, you must jquerify the object.
Exemple : http://jsfiddle.net/FTcpD/

Categories

Resources