Toan Nguyen
Toan Nguyen

Reputation: 11581

Enumerate through elements returned by getElementByClassName in Javascript

I have the following markups and scripts to simulate a simple calculator

HTML:

<input id="txtResult" type="text" readonly="readonly" /><br />
    <input id="txtInput" type="text" /><br />
    <button id="btn7" class="number">7</button>
    <button id="btn8" class="number">8</button>
    <button id="btn9" class="number">9</button><br />
    <button id="btn4" class="number">4</button>
    <button id="btn5" class="number">5</button>
    <button id="btn6" class="number">6</button><br />
    <button id="btn1" class="number">1</button>
    <button id="btn2" class="number">2</button>
    <button id="btn3" class="number">3</button><br />
    <button id="btnClear">C</button>
    <button id="btn0" class="number">0</button>
    <button id="btnClearEntry">CE</button><br />
    <button id="btnPlus">+</button>
    <button id="btnMinus">-</button>

Javascript:

The scripts tried to attach a click event handler to the buttons.

window.onload = function()
{
    var buttons = document.getElementsByClassName("number");

    for (var btn in buttons)
    {
        console.log(btn); //print the value of "buttons", i.e 1, 2 ,3

        btn.addEventListener("click", numberClick, false);  // JavaScript runtime error: Object doesn't support property or method 'addEventListener'
    }


    //However accessing an element directly works !!!
    var btn5 = document.getElementById("btn5");

    btn5.addEventListener("click", numberClick, false);
}

function numberClick()
{
    var input = document.getElementById("txtInput");
    input.value = input.value == "0" ? this.innerText : input.value + this.innerText;
}

The problem here is when I looped through the buttons and tried to attach the event handler, it threw an exception. However, when a button was retrieved directly by using getElementById, the code worked.

Could you please explain why?

Upvotes: 0

Views: 109

Answers (2)

jfriend00
jfriend00

Reputation: 707218

document.getElementsByClassName() returns an array like object that is better iterated like this:

var buttons = document.getElementsByClassName("number");
for (var i = 0; i < buttons.length; i++) {
    buttons[i].addEventListener("click", numberClick, false);
}

You can iterate arrays the way you were (not recommended though because it iterates all enumerable properties not just array elements which can sometimes mess up the code), but if you did, then buttons[btn] would be the object, not btn like you were trying to use.

Upvotes: 2

adeneo
adeneo

Reputation: 318182

A nodeList is array-like, so a regular for loop should be used, and querySelectorAll has better support

window.onload = function() {

    var buttons = document.querySelectorAll("number");

    for (var i=buttons.length; i--;) {
        buttons[i].addEventListener("click", numberClick, false);
    }
}

When using for-in loops, it's

for ( key in object )

so it would be

for (var btn in buttons) {
    buttons[btn].addEventListener
}

Upvotes: 2

Related Questions