Javascript .getElementsByClassName isn't working [duplicate] - javascript

This question already has answers here:
What do querySelectorAll and getElementsBy* methods return?
(12 answers)
Closed 6 years ago.
This code has no errors in console.log, but it doesn't display class name as it should.
document.getElementsByClassName("abc").onmouseover = function(){mouseOver()};
function mouseOver(){
abc.innerHTML = "Class name " + abc.className;
}

The .getElementsByClassName() routine returns a list of elements. You cannot directly add event handlers to all elements via the list as you're attempting to do. You have to iterate explicitly:
var abc = document.getElementsByClassName("abc");
for (var i = 0; i < abc.length; ++i) {
// ...
}
For your purposes, doing that with the Array.prototype.forEach method makes a little more sense, though it looks odd:
var abc = document.getElementsByClassName("abc");
[].forEach.call(abc, function(element) {
element.onmouseover = function() {
element.innerHTML = "Class name: " + element.className;
};
});
Using .forEach ensures that the event handler works properly using a local variable (element) private to each invocation of the loop callback.

document.getElementsByClassName Returns an array-like object of all child elements which have all of the given class names. So you will have to bind the onmousever event with each child object.
https://developer.mozilla.org/en/docs/Web/API/Document/getElementsByClassName
You can try like this.
var elements = document.getElementsByClassName("abc")
for (var i=0; i < elements.length; i++) {
elements[i].onmouseover = function(){mouseOver(i)};
}
function mouseOver(index){
document.getElementsByClassName("abc")[index -1].innerHTML = "Class name " + document.getElementsByClassName("abc")[index -1].className;
}
<div class="abc">
mouse over me
</div>
Edited Answer based on the provided html in comment
<html> <head> </head> <body> <h1 class="abc">Hello everyone</div>
<script type="text/javascript"> var elements = document.getElementsByClassName("abc"); for (var i=0; i < elements.length; i++) { elements[i].onmouseover = function(){mouseOver(i)}; } function mouseOver(index){ document.getElementsByClassName("abc")[index -1].innerHTML = "Class name " + document.getElementsByClassName("abc")[index -1].className; } </script> </body> </html>

Related

Javascript how to pass index value of a class to another class inside a function? [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 6 years ago.
I'm trying to preview image in specific class that has the same index value of another class, from where the user selects an image.
So far I have done this. When I give a specific value to the output class index the image shows up in that specific class
var input = document.getElementsByClassName("input");
var output = document.getElementsByClassName("output");
for (i = 0; i < input.length; i++) {
input[i].onchange = function() {
output[0].src = URL.createObjectURL(event.target.files[0]);
}
}
However when I try to pass the 'i' variable to that class's index the code doesn't work.
var input = document.getElementsByClassName("input");
var output = document.getElementsByClassName("output");
for (i = 0; i < input.length; i++) {
input[i].onchange = function() {
output[i].src = URL.createObjectURL(event.target.files[0]);
}
}
How can I solve this?
In this code you have used a closure function.When the function is invoked, it is created a single context.
Read more about, here.
One method is to use Immediately-invoked function expression, something like this:
for (i = 0; i < input.length; i++) {
(function(index){
input[index].onchange = function() {
output[index].src = URL.createObjectURL(event.target.files[0]);
}
}(i));
}
Here is an example where closures are used in wrong way.
var input=document.getElementsByClassName('abc');
for (i = 0; i < input.length; i++) {
input[i].onclick = function() {
console.log(i);
}
}
<button class="abc">Button1</button>
<button class="abc">Button2</button>
<button class="abc">Button3</button>
As you can see, anything button you clicked, console.log display 3.
Why it is this behavior ?
It is created a single context. When for loop is finished, the value of i remain 3 and whenever you clicked one button, this value is display in console.
How can we resolve this problem ?
One method is to use IIFE, as I mentioned above.
var input=document.getElementsByClassName('abc');
for (i = 0; i < input.length; i++) {
(function(index){
input[index].onclick = function() {
console.log(index);
}
}(i));
}
<button class="abc">Button1</button>
<button class="abc">Button2</button>
<button class="abc">Button3</button>

getElementByID works, getElementsByClassName does not work [duplicate]

This question already has an answer here:
getElementByID works, getElementsByClassName does not [duplicate]
(1 answer)
Closed 7 years ago.
I'm working on a solution where the javascript changes div1 instead of div2.
This code works with getElementbyId but does not work with getElementbyClassName. Why does this not work?
function refer(Div1, Div2) {
if (document.getElementByClassName('Div1')) {
if (document.getElementByClassName('Div1').style.display == 'block') {
var elems = document.getElementsByClassName('Div2');
for(var i = 0; i < elems.length; i++) {
elems[i].style.display = 'block';
}
var elem = document.getElementsByClassName('Div1');
for(var i = 0; i < elem.length; i++) {
elem[i].style.display = 'none';
}
}
}
}
Here is an example how to use getElementsByClassName: Fiddle
Is this working for you?
array = document.getElementsByClassName('div1');
for (i = 0; i < array.length; i++) {
array[i].style.backgroundColor = "red";
}
In Chrome and Edge works with no issue.
You are using a array as an object, the difference between getElementbyId and
getElementsByClassName is that:
getElementbyId will return you an object.
getElementsByClassName will return you an array.
getElementsByClassName
The getElementsByClassName(classNames) method takes a string that
contains an unordered set of unique space-separated tokens
representing classes. When called, the method must return a live
NodeList object containing all the elements in the document that
have all the classes specified in that argument, having obtained the
classes by splitting a string on spaces. If there are no tokens
specified in the argument, then the method must return an empty
NodeList.
https://www.w3.org/TR/2008/WD-html5-20080610/dom.html#getelementsbyclassname
getElementById
The getElementById() method accesses the first element with the specified id.
http://www.w3schools.com/jsref/met_doc_getelementbyid.asp
in your code the lines:
1 if (document.getElementByClassName('Div1')) {
2 if (document.getElementByClassName('Div1').style.display == 'block') {
will NOT work as expected: specially the second(2) line, cos the getElementByClassName will return an array, and the array will NOT have the style property, you gonna access each element by iterating them.
That's why the function getElementById was working for you, this function will return you the direct object , and so you will be able to access the style property.
One working code:
function refer(Div1,Div2) {
var elem = document.getElementsByClassName('Div1');
var elems = document.getElementsByClassName('Div2');
for(var i = 0; i < elem.length; i++) {
if (elem[i]) {
if (elem[i].style.display == 'block') {
elem[i].style.display = 'none';
for(var i = 0; i < elems.length; i++) {
elems[i].style.display = 'block';
}
}
}
}
}

iterate through all available getElementsByClassName nodes [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
adding 'click' event listeners in loop [duplicate]
(5 answers)
Closed 7 years ago.
For my project, I am required to get the collection of all the elements which have the same class. So, I am doing it with getElementsByClassName.
var tabs = document.getElementsByClassName("tab");
if (tabs) {
for (var i = 0; i < tabs.length; i++) {
var tab = tabs[i];
console.log(tab); // which outputs as 'undefined'..
console.log(i); // which outputs the nos of the total nodes available with class 'tab'
}
}
I have to retrieve all those elements(which has class 'tab') and apply it another class (say 'bat')..
My question is, why it consoles out undefined as above?? and how can I be able to iterate through all the required nodes sequentially. Is there any code available which can do this??
EDIT ::
Forget to add it..
When clicked on any tab which has 'tabs' class, it always returns the same result..
var tabs = document.getElementsByClassName("tab");
if (tabs) {
for (var i = 0; i < tabs.length; i++) {
var tab = tabs[i];
tab.addEventListener("click", function() {
console.log(tab[i]); // always returns undefined
console.log(tab); // always returns the last element in the list
console.log(i); // always returns the length of that list (in my case its 3)
}, false);
}
}
How can I be able to iterate through all the available elements sequentially.
You can change a NodeLiist into an array. Btw, your tab[i] should be tabs[i] I think.
var tabs = document.getElementsByClassName('tab');
var tabArray = Array.prototype.slice.call(tabs);
for(var i = 0; i < tabArray.length; i++) {
console.log(tabArray[i].id);
console.log(i);
tabArray[i].innerHTML = "t"+(i+1);
};
<div id="t1" class="tab">t</div>
<div id="t2" class="tab">t</div>
<div id="t3" class="tab">t</div>
<div id="t4" class="tab">t</div>
<div id="t5" class="tab">t</div>
<div id="t6" class="tab">t</div>
<div id="t7" class="tab">t</div>
<div id="t8" class="tab">t</div>
Be careful with getElementsByClassName(), as said in mozilla docs the return is a array-like object not a array. Another point is that return is a live HTMLCollection so if you want to change the class name through a loop the collection will be live updated on the fly and will cause unexpected behaviors.
I made a example with class change case. Check complete code on link below.
http://codepen.io/renatocolaco/pen/VemMNy
function btnClick(event){
event.preventDefault();
//action goes here
var boxes = document.getElementsByClassName("box");
console.log("fouded elements: " + boxes.length);
var element = boxes.item(0);
while(element){
element.className = "another_box";
element = boxes.item(0);
}
//doesn't work
//var cache = boxes.length;
//for(var i = cache; i < boxes.length; i++){
// console.log(boxes[0]);
// boxes[0].className = "another_box";
// }
//doesn't work
//Array.prototype.forEach.call(boxes, function(element, index, array){
//array[index].className = "another_box";
//});
}
Update:
The second problem, when you are adding event to the tabs, you have a closure problem.
This is because, at the point that the onclick method is invoked (for any of the tabs), the for loop has already completed and the variable i already has a value(the size of your collection).
Wrap your code inside a self executed function like this:
(function (i) {
tab.addEventListener('click', function() { console.log(i); });
})(i);
Have you used JQUERY before? That might be an easier path. This way you can use $(".tab"). You can also use .forEach() instead of a for loop? Might make it more simple
Also, Paul's example seems to be working, can you provide a non working JSfiddle?

Event for multiple elements with the same class name [duplicate]

This question already has answers here:
getElementsByClassName onclick issue [duplicate]
(5 answers)
Closed 9 years ago.
I have the following code:
var abbrs = document.getElementsByClassName("hover");
abbrs.onmouseover=function() {
console.log(this);
};
It should trigger when I hover over an element with the class "hover", but it is not working.
What am i doing wrong?
As its name suggests document.getElementsByClassName returns a list of elements, with the hover as their className, so you can do it like:
var i=0,
len = abbrs.length,
abbrs = document.getElementsByClassName("hover");
for( ; i < len ; i++){
abbrs[i].addEventListener("mouseover", function(event){
//...
});
}
Although it answers the question but in terms of a better coding practice we better avoid from creating functions in loops. So the better practice could be something like this:
var i=0,
len = abbrs.length,
abbrs = document.getElementsByClassName("hover");
fnction addEvent(abbr){
abbr.addEventListener("mouseover", function(event){
//...
});
}
for( ; i < len ; i++){
addEvent(abbrs[i]);
}
document.getElementsByClassName returns either a NodeList or HTMLCollection depending on your current browser and version.
To add event listeners to all of the items in the "abbrs" collection/list you would need to do:
for(i=0; i< abbrs.length; i++) {
abbrs[i].onmouseover=function() {...};
}
Alternately, using jQuery:
$(".hover").on("mouseover", function() {...});
See the code below (I assume you are not using jquery)
var abbrs = document.getElementsByClassName("hover");
var index,l=abbrs.length;
for (index = 0; index < l; ++index) {
console.log(abbrs[index]);
abbrs[index].onmouseover = function() {
console.log(this);
}
}

Passing values to onclick [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 8 years ago.
If I create a whole lot of HTML elements using a loop, like
for (i= 1; i < 100; i++) {
var my_element = document.createElement ("td");
row.appendChild (my_element);
my_element.onclick = function () {my_function (i));
}
then when the element is clicked, the value of i passed to my_function is always 100, regardless of what number element is calling it. I have worked around this by using
my_element.id = "something"+i;
my_element.onclick = function (e) {my_function (e.target.id)};
(For Internet Explorer, the target needs to be srcElement, apparently.) I am curious to know whether there is any way to create the function without having to add the ID to the element like this.
The value of i changes with each iteration of the loop. You need a closure to capture the value of i:
(function(i) {
my_element.onclick = function () {my_function (i)};
}(i))
If you write a function which builds you a handler function, you can use the new scope which that gives you to ensure that you get the number you want. For example:
function BuildHandler (i) { return function () { alert(i); };
for (i= 1; i < 100; i++) {
var my_element = document.createElement ("td");
row.appendChild (my_element);
my_element.onclick = BuildHandler(i);
}
if I were you I will use Jquery (or prototype or whatever js frameworks that available)
on each elements you should add attributes like myid for example so that when you did on click you can retrive it.
for(i=1; i ++ ; i<100){
var myelement = "<td myid='something"+i+"' class='myTD'></td>" ;
row.append(myelement);
}
....
$(document).ready(function(){
$('.myTD').click(function(){
var id = $(this).attr('myid');
my_function(id);
});
});
I did this trick on my web app :)

Categories

Resources