I'm playing around with .classList and I'm getting some odd errors in my console. Here's my demo
Basically, I have an array of images all with the class of child and I'm doing a javascrpt .querySelectorAll to store those images in a variable for further manipulation.
var el = document.querySelectorAll('.child');
console.log(el.classList;);
el.classList.add("someClass");
But when I open up my console I'm getting some errors .
This one in reference to .classList;
undefined
And this one in reference to .classList.add();
Uncaught TypeError: Cannot read property 'add' of undefined
Yet, when I switch to looking up elements by ID, the errors go away. Now using IDs isn't out of the question, but ideally I'd like to keep things to class Names. Any idea what's going on?
el is a collection, not a single DOM element. classList does not make much sense for an array, though. So what you might want to do:
var product = document.getElementsByClassName('product');
var el = document.querySelectorAll('.child');
for(var i = 0; i < el.length; i++) {
el[i].classList.add("someClass");
console.log(el[i].classList);
}
Related
I have the following code written in my .js file:
var tiles = document.querySelectorAll(".tile");
var tileNumbers = ["one", "two", "three", "four"];
for(var i = 0; i < tiles.length; i++){
var num = Math.floor(Math.random() * tileNumbers.lenth);
tiles.classList.add(tileNumbers[num]);
tileNumbers.pop(num);
}
The .tile are 4 <div>'s in the .html file, and I am trying to add a class each of the four tiles separately. The classes are held in tileNumbers. When I run the code in Chrome I get the error:
"Uncaught TypeError: Cannot read property 'add' of undefined."
I am pretty sure everything is spelled correctly. Please help!
You want to call add on the tile, but try to access the add function of the tiles array itself. This does not exist.
What you need to do is to access the add function of each individual tile. To do so, first get it:
var tile = tiles[i];
Then, change your call to
tile.classList.add(…);
(You could also omit the temporary variable tile, and use tiles[i].classList.add directly. But IMHO using a dedicated variable makes the code more clear to read.)
Another option, which may be even better, is to use forEach. Since you use the i only for accessing the current element and nothing else, you basically want to perform an action on each element. You can do it like this as well (and, for bonus points, this even protects you against off-by-one errors):
tiles.forEach(function (tile) {
// ...
});
Then, within the function body, you automatically have a variable tile that you can access in the way you want to.
That's it :-)
tiles[i].classList.add(tileNumbers[num]);
Not
tiles.classList.add(tileNumbers[num]);
I've got some JS code here. Basically, I am trying to change the ID of an element to some value from a previous variable.
Here's what I got so far;
function() {
var colorarray = [ "RANDOMCOLOR_0", "RANDOMCOLOR_1", "RANDOMCOLOR_2" ];
var RANcolorarray = colorarray[Math.rsound(Math.random() * (colorarray.length - 1))];
document.getElementsByClassName('RANDOMCOLOR').setAttribute('id', RANcolorarray);
}
This code throws an error in Chrome for line 4: Uncaught TypeError: undefined is not a function which is weird because JsLint finds no errors.
I also tried using the other way to setting id's;
document.getElementsByClassName('RANDOMCOLOR').id = RANcolorarray;
However, although this method does not throw an error on chrome or jslint - it does not work at all after inspecting the element.. :/
Any ideas?
document.getElementsByClassName('RANDOMCOLOR') returns a list of DOM nodes (even if there's only one match) so you can't just call .setAttribute() on the list as the list doesn't have that method.
You can either get the first item out of the list and call .setAttribute() on that one or use a for loop to iterate through the list and call it on all of them. Of course, since you're setting the id, you should not be setting multiple elements to the same id, so I'll assume you just want one element:
document.getElementsByClassName('RANDOMCOLOR')[0].id = RANcolorarray;
Or, a little more safe:
var elems = document.getElementsByClassName('RANDOMCOLOR');
if (elems && elems.length) {
elems[0].id = RANcolorarray;
}
I'm am battling with a javascript function I'm working on.
Inside a for loop I'm iterating all elements with class "visible", inside that loop
I'm preforming two actions.
elements[i].removeAttribute("class");
elements[i].setAttribute("class", "hidden");
For some reason only 1 is valid. 2 produces an error saying:
Uncaught TypeError: Cannot call method 'setAttribute' of undefined
Even when I log elements[i] using console.log; after the first console.log call
the element exists, but on the second console.log elements[i] is 'undefined'
What the hell am I missing here, this is driving me crazy, if my laptop wasn't so expensive
it would have been broken by now. Help :(
Here's the function:
function hide_visable_elements()
{
// remove body EventListener
var body = document.getElementsByTagName("body");
body[0].removeEventListener("click", hide_visable_elements, true);
var elements = document.getElementsByClassName("visible");
for (var i = 0; i < elements.length; i++)
{
console.log(elements[i]); // Works like a swiss clock
elements[i].removeAttribute("class");
console.log(elements[i]); // why elements[i] is 'undefined' now ???
elements[i].setAttribute("class", "hidden"); // << turns to useless code
}
}
This is because getElementsByClassName returns a NodeList, which is live. That is, it updates itself when the elements it refers to change.
When you remove the class attribute from an element in the NodeList, it gets removed from that list (since it no longer has the visible class name).
You don't actually need to remove the attribute. Just setting it will do the job just as well. But since the NodeList is changing as you manipulate the elements it contains, you need to count backwards through it (as each time you change one element of it, it is removed so the length decreases by one):
for (var i = elements.length - 1; i >= 0; i--) {
elements[i].setAttribute("class", "hidden");
}
getElementsByClassName is a live NodeList so changing className of the items immediately affects whole list. I would recommend use querySelectorAll insead.
Plus instead of var body = document.getElementsByTagName("body"); use document.body.
I think that the problem is elements[i].removeAttribute("class"); since you selected the element using a class getElementsByClassName("visible"); . I think so when you remove class attribute completely from the element things are going wrong.
Try some tweak with the code. You are not suppose to remove attribute class if you are planning to use the same element which is selected using class attribute.
I am still trying to learn pure javascript seeing as I skipped it and went to learn jQuery, though I don't want a library anymore. I want speed, anyways I have a few questions about pure JavaScript.
First Question :
var profile = document.getElementsByClassName("postprofile-details");
var details = profile.getElementsByTagName("dd");
details[0].style.display = "none";
I keep getting an error of
TypeError: Object #<NodeList> has no method 'getElementsByTagName'
How would I go about this?
Next question which is pertaining to the same code above basically, I know jQuery has a .prepend() and .append() so how would I insert additional HTML to the var profile above?
Third and Last Question
I would like to figure out this sort of issue, I've been learning the loop function instead of the .each() and this is what I have come up with but getting errors
var a = document.getElementsByClassName('postprofile-details');
for (var i =0; i<a.length; i++) {
a[i].getElementsByTagName('dd').style.display='none';
}
Question at hand is how do I actually go about making sure I am selecting the loop inside the for loop function? Do I
A) a[i].getEle...
or
B) a.getEle...
Any answers to these questions would be helpful, I'm just tired of using jQuery
With the Follow Answers and Comments
Let me see if I can write this
var profile = document.getElementsByTagName('postprofile-details');
for (var i=0; i<profile.length; i++) {
var dd = profile[i].getElementsByTagName('dd');
dd.style.display='none';
var newEle = document.createElement('div');
newEle.id = 'toggle';
profile[i].appendChild(newEle);
}
Please let me know if any issue in my code are visible thank you.
TypeError: Object # has no method 'getElementsByTagName'
You should use:
profile[index].getElementsByTagName("dd");
With the desired node, you can not use getElementsByTagName on a node list.
Next question which is pertaining to the same code above basically, I know jQuery has a .prepend() and .append() so how would I insert additional HTML to the var profile above?
profile[index].appendChild(newNode);
Last answer:
As the first answer, you need to iterate all the nodeList getElementsByTagName\ getElementsByClassName returns.
I am trying to check whether the a css class is used inside the DOM or not. So, I have
var x = document.getElementsByClassName('classname');
When I print x out, I get a [object NodeList] for classes that exist on the page and classes that dont. Is there a property of x that I can access ? Like the tag name or something. Would be great if somebody can tell me the different properties of x and the ways I can access them.
Thank you :)
Notice that it's plural:
var x = document.getElementsByClassName('classname');
^
You need to iterate over x to get the individual elements:
for (var i = 0; i < x.length; i++) {
var element = x[i];
console.log(element);
}
Make sure to add fallback support for Internet Exploder: http://ejohn.org/blog/getelementsbyclassname-speed-comparison/
If you just want to check for the presence of a class in the document, you can also use querySelector.
var x = document.querySelector('.classname');
It returns null if no elements have that class, otherwise the first element with that class name. If you want all elements using classname:
var x = document.querySelectorAll('.classname');
Now x is null if the class is not used in the document, otherwise a Nodelist, containing all elements with class classname, which can be iterated the way Blender showed. In that iteration you can, for example, retrieve the elements tagName or its id. Like:
for (var i=0;i<x.lenght;(i=i+1)){
console.log(x[i].id + ': ' + x[i].tagName);
}
document.querySelector is available in all modern browsers, and for IE version 8 and up.
I almost always use document.querySelector (which: "Returns the first element within the document that matches the specified group of selectors"), which returns an element object and it's.
I don't know why but in my Chrome's console I write:
var img = document.getElementsByClassName('image__pic');
img[0]...
img[0], despite its happy existance, it doesn't generate any further attributes/methods to use in the completion window. Like there were none (even though I could use img[0].src for instance)
On the other hand:
var imgq = document.querySelector('.image__pic')
Gives me very useful autocompletion on the Console:
As far as its browser support it is phenomenal:
It is also less tricky to use, because getElementsByClassName returns an HTMLCollection, which is a little beast of its own.
Another plus for querySelector is its versatility: any kind of CSS selector goes!
On the negative side, querySelector is a bit slower, but I think it's worth it.