Search code examples
javascriptdomlive

HTMLCollection adding different attributes affects the live collection differently, need explanation


so we all know document.getElementsByClassName and document.getElementsByTagName are live HTMLCollections.

I googled and can't seem to find the answer to this, maybe I just don't get it, who can explain it to me?

So I made 2 examples, one with adding a class attribute, the other with bgcolor. Why does the first act like expected and the other gets it's job done...

Why does the TagName one work differently even it's a HTMLCollection in the first example?

How can I know which will work normally and which wont??

https://jsfiddle.net/adkuca/84ryjp7s/2/

https://jsfiddle.net/adkuca/f1o9h7be/

var ran = document.getElementsByClassName('wasd');
/*var ran = document.getElementsByTagName('td');*/

document.getElementById('btn').addEventListener('click', func);
function func() {
		console.log(ran); //HTMLCollection, all 6
    console.log(ran.length); //6 with both
    for (let i = 0; i < ran.length; i++) {
        ran[i].setAttribute("class", "green");
    }
    console.log(ran); //HTMLCollection, all 6 with TagName, every 2nd with ClassName
    console.log(ran.length); //6 with TagName, 3 with ClassName
}
tr, td {
    border: 1px solid black;
    height: 20px;
    width: 20px;
}

.green {
  background-color: green;
}
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
    <button id="btn">func</button>
    <table>
        <tr>
            <td class="wasd"></td>
            <td class="wasd"></td>
            <td class="wasd"></td>
        </tr>
        <tr>
            <td class="wasd"></td>
            <td class="wasd"></td>
            <td class="wasd"></td>
        </tr>
    </table>
    </body>
</html>

var ran = document.getElementsByClassName('wasd');
/*var ran = document.getElementsByTagName('td');*/

document.getElementById('btn').addEventListener('click', func);
function func() {
		console.log(ran); //HTMLCollection, all 6
    console.log(ran.length); //6 with both
    for (let i = 0; i < ran.length; i++) {
        ran[i].setAttribute("bgcolor", "green");
    }
    console.log(ran); //HTMLCollection, all 6
    console.log(ran.length); //6 with both
}
tr, td {
    border: 1px solid black;
    height: 20px;
    width: 20px;
}
<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
    <button id="btn">func</button>
    <table>
        <tr>
            <td class="wasd"></td>
            <td class="wasd"></td>
            <td class="wasd"></td>
        </tr>
        <tr>
            <td class="wasd"></td>
            <td class="wasd"></td>
            <td class="wasd"></td>
        </tr>
    </table>
    </body>
</html>


Solution

  • They both work normally and in the same way. The className appears to work differently because you're effectively removing elements from the list you're working with, while you're going through it.

    when you use setAttribute("class", "green"); you're replacing the "wasd" class with "green"

    This will work if you add a class instead of replacing the current one using ele.classList.add(class)

    https://jsfiddle.net/84ryjp7s/3/