How to chain getElementById and getElementByClassName - javascript

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

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.

Quick Javascript thought about document.getElementByClassName for fixing error

Quick JS question :
if you do something like :
var text = document.getElementByClassName("grid3").innerText;
what is the best way if you have multiple elements with that class?
what is the best way if you have multiple elements with that class?
It depends which element you want to reference... your example will always fail because that method returns a NodeList regardless of the number of elements. Note that it's getElementsByClassName (plural "elements").
If you want to get the first:
var text = document.getElementsByClassName("grid3")[0].innerText;
If you want to get them all (in an array):
var allText = [].map.call(document.getElementsByClassName("grid3"), function (elem) {
return elem.innerText;
});
Its document.getElementsByClassName("grid3") with s...you will always get back an array of Objects. Therefore innerText will not work there.
You could get the innerText of single elements in this array like this:
var el = document.getElementsByClassName("grid3");
var text = el[0].innerText;
Or if you have just one element with that class, give it a id and use
var el = document.getElementById("yourelementsid");
Here is a fiddle that shows how it works and not works:
Fiddle
There is no method document.getElementByClassName, you lost "s".
document.getElementsByClassName always returns an array (or array-like object), so you have to loop througt this array to find what you want.
document.getElementByClassName() return a list of elements so you can use it as array.
var textArr = document.getElementByClassName("grid3");
for(var i = 0; i< textArr.length; i++){
// here is your text
var text = textArr[i].innerText;
}

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';
}

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.

call a function with a specific index value of nodelist

Is it possible to call a function on specific index value of nodelist which is storing div like following :
var txtElem = txtdiv.getElementsByTagName("div");
the thing i want is that i am storing list of divisions in txtElem nodelist now i want to call a function on click event of the 3rd div stored in nodelist. The divisions are created dynamically and they don't have any id so they are not accessible by id.
from what you asked, it seems like this will do:
function toPseudoArray(nodeList) {
var ar = [];
for(var i in nodeList)
if(nodeList[i].nextSibling) // or for that case any other way to find if this is an element
ar.push(nodeList[i]);
return ar;
}
Pass your nodeList to this function, use what it returns as an array that contains your elements, and only your elements.
By the way, you could directly call function on a specific element simply using my_fab_function(txtElem[0]); -- of course, until you don't exceed the count.
The question is quite unclear. Seeing the jQuery tag, these come to my mind:
A way to call a jQuery function on a specified index using .eq():
var n = 1; //the index you need
$(txtElem).eq(n).css('color', 'red');
Simple Javascript to get the DOM element:
var n = 1; //the index you need
var elem = txtElem[n]; //elem will hold the DOM element
//call simple DOM methods on it:
var s = elem.innerHTML;
//you can also call jQuery functions on it:
$(elem).css('color', 'red');
By the way txtElem is not an object, it is a NodeList, an "array-like object".

Categories