I did a getElementsByTagName("li") in my DOMDocument, but I don't have the inner HTML of each li elements, just the unlike a getElementById. How to get the HTML for a getElementsByTagName?
The word Elements in getElementsByTagName is plural.
It doesn't return an element, it returns a NodeList, which is like an array.
Loop over it (for (var i = 0; i < nodelist.length; i++)) and deal with each member in turn.
getElementsByTagName returns an array of elements. You have to loop through it to extract the innerHTML (make sure you really want the HTML, and not just the text!)
for (var i=0; i<x.length; i++) { //x = the list of elements
var derp = x[i].innerHTML;
}
Or if you wanna be fancy, use the prototype method forEach and call.
[].forEach.call(document.getElementsByTagName("li"), function(element) {
element.innerHTML;
});
I suggest replacing innerHTML with textContent however, since you said you wanted text.
Related
I have this HTML code
<div id="first">
<div id="second">
</div>
</div>
I want to append a child to each existing div.
When I use this code
function appendC() {
var divsVar = document.getElementsByTagName("div");
for (var i = 0; i < divsVar.length; i++) {
var new_div = document.createElement("div");
div[i].appendChild(new_div);
}
}
the function it goes into an infinite loop. But I can't understand why.
When the function is called, it assigns to var divsVar an array with 2 divs in my example. Never executed again, unless I call again the function. But the divsVar.length is changed in every loop. How is this possible?? The divsVar.length should stay as constant??
If I use a temp variable like that
function appendC() {
var divsVar = document.getElementsByTagName("div");
var _temp = divsVar.length;
for (var i = 0; i < _temp; i++) {
var new_div = document.createElement("div");
div[i].appendChild(new_div);
}
}
it work like a charm.
The .getElementsByTagName() method returns a live HTMLCollection.
You can either turn the collection into an array (e.g. [].slice.call(collection)), or use another method such as .querySelectorAll() which returns a static NodeList.
https://developer.mozilla.org/en-US/docs/Web/API/Element/getElementsByTagName
https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll
getElementsByTagName() returns an object containing a live HTMLCollection. This is updated whenever you update the dom. In your for loop, after every iteration, the length property is evaluated again on the current dom.
Because you are adding divs to the dom, this loop will run forever.
The reason this works with a _temp variable is because you only evaluate the length of the HTMLCollection once.
I think the best solution would be to evaluate the length beforehand, just like your last example.
getElementsByTagName() method returns a live HTMLCollection of elements with the given tag name.
This means that even though you're not calling it again, it's still being updated. To fix this simply use
document.querySelectorAll("div")
which returnsA non-live NodeList containing one Element object for each element that matches at least one of the specified selectors.
I'm trying to grab all tags within a div called "states", and then uncheck them (they are all checkboxes).
document.getElementById("states").getElementsByTagName("input").checked = false;
For some reason it's not working, though it DOES work if I give them each IDs and use this code for each:
document.getElementById("checkboxName").checked = false;
Any thoughts?
getElementsByTagName returns a NodeList. On it you can just do a simple for loop and set checked for each element. Setting the same id for each one of them is not a correct way of doing this as semantically there shouldn't be more than one element with the same id.
getElementsByName() returns a NodeList. A NodeList does not have a 'checked' property, is a collection of Nodes. What you're trying to do would be very easy with jQuery. But you cand do it your way, just enumerate the NodeList with a for loop (NodeList is Array-like) and change the checked property.
var checkboxes = document.getElementById("states").getElementsByTagName("input");
for (var i = 0; i < checkboxes.length; i++) checkboxes[i].checked = false;
With jQuery:
$('#states input[type="checkbox"]').prop('checked', false);
check it here
I have a div with id "productPriceContainer" and within this div a class "price".
I want to access the innerHTML of class "price" since I have other classes called "price" as well.
Can I chain something like this?
document.getElementById(productPriceContainer).getElementsByClassName(price).innerHTML
If not what is the correct way of doing what I need?
Thanks
If you have one element with class price in the element with id productPriceContainer, you can do
document.getElementById('productPriceContainer')
.getElementsByClassName('price')[0].innerHTML
Notice the s in getElementsByClassName. It explains why you can't chain just like that. You don't have a function called getElementByClassName because, contrary to the id, there is no unicity of elements having a given class.
Almost.
If you want to pass strings, then you have to pass strings and not undefined variables
getElementsByClassName (plural!) returns a NodeList, not a Node, so you have to loop over it to get the Nodes (on which you can then use innerHTML.
You are passing a variable, not a String to the method -> it should be "price" not price.
The Method for retrieving Nodes by a classname is getElementsByClassName you were missing the "s"
It returns an Array of DOM Elements so you have to iterate over the childs of your container
For example:
document.getElementById("productPriceContainer").getElementsByClassName("price")[0].innerHTML = "Asdf";
sets the innerHTML of the first DOM element with the class "price" within your container Element to "Asdf"
Iterating over the Elements could look like this:
var elements = document.getElementById("productPriceContainer")
if(elements) {
var classes = elements.getElementsByClassName("price");
for (var i = 0; i < elements.length; i++) {
elements[i].innerHTML = "Asdf" + i;
}
}
Here is a JSBin
I have a script that I'm running and I want to it to select all the ID's or Class's instead of just the first one.
<script type = "text/Javascript" >
function color(){
var d=document.getElementsByClassName("black")[0];
d.setAttribute("style", "background-color:#333;");
}
</script>
The [0] in document.getElementsByClassName("black")[0] means that you're actually discarding all but the first, after selecting them. Use a loop if you want to iterate over the value returned by gEBCN.
Use document.getElementsByTagName('*') if you want all elements.
function color() {
var allElements = document.getElementsByTagName('*');
for (var i=0; i<allElements.length; i++) {
allElements[i].setAttribute('style', 'background-color:#333;');
}
}
To get all the elements with a certain ID, you can rely on querySelectorAll, as in
var d = document.querySelectorAll("#temp");
Keep in mind some things:
It's semantically wrong, even if not syntactically, to have multiple elements with the same id.
querySelectorAll return a NodeList object, not a live collection. This means that if you add another element with id "temp", that won't be in the collection you got and you have to call querySelectorAll again.
querySelectorAll isn't supported by IE7 and previous versions.
You already have an answer for getElementsByClassName.
Once the page has been loaded, I would like to append an additional element for each existing elements on the page.
I tried something like this:
var divs=document.getElementsByTagName('div');
for(i=0;i<divs.length;i++){
newDiv=document.createElement('div');
divs[i].appendChild(newDiv);
}
Just a warning this will actually freezes the browser because the divs variable is dynamic and divs.length just gets larger and larger each time the loop goes.
Is there a way to determine the number of tags when the DOM is normally loaded for the first time and have a chance to work with the elements statically.
I can't there of another solution so far.
Thanks so much.
Dennis!
The problem is that DOM collections are live, and when the underlying document structure is changed, it will be reflected automatically on the collection, that's why when the length property is accessed it will contain a new length, a common approach is to cache the length before starting the loop:
var divs=document.getElementsByTagName('div');
for(var i = 0, len = divs.length;i<len;i++){
var newDiv = document.createElement('div');
divs[i].appendChild(newDiv);
}
Also notice that you should declare all your variables with the var statement, otherwise it might become global.
Edit: In this case, since you are appending child nodes of the same tagName, the collection will be modified, and the indexes will no longer match, after the first iteration, the index 1 will refer to the newDiv object from the previous iteration, as #Casey recommends it will be safer to convert the collection to a plain array before traversing it.
I use the following function:
function toArray(obj) {
var array = [];
// iterate backwards ensuring that length is an UInt32
for (var i = obj.length >>> 0; i--;) {
array[i] = obj[i];
}
return array;
}
//...
var divs = toArray(document.getElementsByTagName('div'));
//...
Like you said, the divs variable is dynamic, so you have to convert it into an array (which is static) before you use it.
var nodeList = document.getElementsByTagName('div');
var divs = [];
for (var i = 0; i < nodeList.length; i++)
divs.push(nodeList[i]);
// loop again and append the other divs
Another (more elegant) way to do this is:
var divs = Array.prototype.slice.call(document.getElementsByTagName('div'));
But alas, this method does not work in IE.
Using jQuery, this is pretty straight forward. You can get a reference to all the existing divs or any other element on the page and then append a new element very easily without needing to create an explicit loop. Hope this help.
$('div').each(function(){
var newDiv = document.createElement('div');
$(this).append(newDiv);
});
document.getElementsByTagName() does NOT return a plain array, but an instance of HtmlCollection, which behaves like an array, but in fact presents some kind of view to all elements with the given element name in the document.
So, whenever you insert something into the DOM, the length property of divs will be updated too - of course.
So, besides other answers here, this behaviour should make sense now ;-)