getElementsByTagName within a getElementByID - javascript

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

Related

for loop condition evaluation

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.

GetElementsByTagName - No HTML

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.

How can I replace one class with another on all elements, using just the DOM?

I just want to change a classname to another one.
I've tried using
document.getElementsByClassName("current").setAttribute("class", "none");
but it doesn't work. I'm new at javascript.
Explanation
document.getElementsByClassName returns an HTMLCollection, not just an array of elements. That means that the collection is live, so in this specific situation, it retains the requirement that it will always hold all elements with the class "current".
Coincidentally, you are removing the very class that the collection depends on, therefore updating the collection. It would be totally different if you were setting the value property (for example) in the loop - the collection wouldn't be affected, because the class "current" wasn't removed. It would also be totally different if you were adding a class, such as el.className += " none";, but that isn't the case.
A great description from the MDN docs:
HTMLCollections in the HTML DOM are live; they are automatically updated when the underlying document is changed.
Approach 1
An easy way to overcome all this pandemonium is by looping backwards.
var els = document.getElementsByClassName('current'),
i = els.length;
while (i--) {
els[i].className = 'none';
}
DEMO: http://jsfiddle.net/fAJgT/
(the code in the demo has a setTimeout, simply so you can see the original border color at first, then after 1.5 seconds, see it change)
This works because it modifies the last item in the collection - when it is modified (and automatically removed), move onto the item before it. So it doesn't suffer any consequences of the automatic removal.
An alternate setup, doing the same thing, is:
for (i = els.length; i >= 0; i--) {
Approach 2
Another answer made me realize you could just continually operate on the first item found. When you remove the specific class, the element is removed from the collection, so you're guaranteed that the first item is always a fresh item in the collection. Therefore, checking the length property should be a safe condition to check. Here's an example:
var els = document.getElementsByClassName('current');
while (els.length) {
els[0].className = 'none';
}
DEMO: http://jsfiddle.net/EJLXe/
This is basically saying "while there's still items in the collection, modify the first one (which will be removed after modified)". I really wouldn't recommend ever using that method though, because it only works specifically because you end up modifying the collection. This would infinitely loop if you were not removing the specific class, or with a normal array or a non-live collection (without spliceing).
Approach 3
Another option is to slice (shallow copy) the collection into an array and loop through that normally. But I don't see any reason/improvement to do that. Here's an example anyways:
var els = document.getElementsByClassName('current'),
sliced = Array.prototype.slice.call(els), i;
for (i = 0; i < sliced.length; i++) {
sliced[i].className = 'none';
}
DEMO: http://jsfiddle.net/LHe95/2/
Approach 4
Finally, you could use document.querySelector - it returns a non-live NodeList (therefore you can loop like normal), and even has better support in browsers than document.getElementsByClassName does. Here's an example:
var els = document.querySelectorAll('.current'),
i;
for (i = 0; i < els.length; i++) {
els[i].className = 'none';
}
DEMO: http://jsfiddle.net/xq8Xr/
References:
document.getElementsByClassName: https://developer.mozilla.org/en-US/docs/DOM/document.getElementsByClassName
HTMLCollection: https://developer.mozilla.org/en-US/docs/DOM/HTMLCollection
slice: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/slice
querySelectorAll: https://developer.mozilla.org/en-US/docs/DOM/Document.querySelectorAll
document.getElementsByClassName("current") returns a HTMLCollection, not an HTMLElement. You can access elements in the list the same way you would access an array.
The following will change the class of the first element in the HTMLCollection.
document.getElementsByClassName("current")[0].setAttribute("class", "none");
However, you do not have to use the setAttribute method, you can just set the className property of the element.
element.className = 'none';
Please note that HTMLCollection are live, wich means that as soon as the element will not have the current class name anymore, the element will be removed from the array, so to avoid any issues you could iterate over it using the following approach:
var list = document.getElementsByClassName("current");
while (list.length) {
list[0].className = 'none';
}

How to chain getElementById and getElementByClassName

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

Select all ID's or Class's with getElementBy

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.

Categories