1

I'm trying to make a simple calculator and am stuck after trying to using the getAttribute method to retrieve my custom data-* attribute.

I made sure the var used to store the elements does indeed house them

<button type="button" class="btn btn-orange" data-num="*">*</button>
var btns = document.querySelectorAll(".btn");
for(var i = 0; i < btns.length; i++){
    btns[i].addEventListener("click", function(){
        var number = btns[i].getAttribute("data-num");
        screen.value += number;
    });
}

There are 15 buttons in total with class="btn". I have checked in the console and btns does indeed hold 15 elements. I don't understand why getAttribute("data-num") is returning undefined when I click any of the buttons with the stated class.

TylerH
  • 20,799
  • 66
  • 75
  • 101

2 Answers2

2

You can use this inside function definition instead of btns[i] as below:

var btns = document.querySelectorAll(".btn");
for(var i = 0; i < btns.length; i++){
    btns[i].addEventListener("click", function(){
        var number = this.getAttribute("data-num");
        screen.value += number;
    });
}

Basically you have created click event function for each button and you are using i inside these function. When this function executes, it checks i value which will be the last value of loop, (if you have 6 .btn class then i will have 6) because you are not binding i current value with function. So on each click, you will get last value which will break code.

To avoid this, you can either use above code or can bind variables in function as below:

var btns = document.querySelectorAll(".btn");
for(var i = 0; i < btns.length; i++){
    btns[i].addEventListener("click", function(iBindededValue){
        var number = btns[iBindededValue].getAttribute("data-num");
        screen.value += number;
    }.bind(this, i));
}

Here we can bind i with current value with each function and can use that. You can refer bind function to check its functionality. Hope it helps you to understand its flow, Cheers!!

Rohit Mittal
  • 2,064
  • 2
  • 8
  • 18
0

The problem is that i is mutated but you're using it INSIDE the event listener. If you log i when adding the event listeners, you'll get 0, 1, 2, 3, as expected. However, if you log i inside the event listener, i is ALWAYS be 4, and so btns[i] is undefined.

Simply keep a separate reference of i, or better yet of btns[i] as below:

var btns = document.querySelectorAll(".btn");

for(var i = 0; i < btns.length; i++){
    btn = btns[i];
    btn.addEventListener("click", function() {
        console.log(i, btns[i]); // i == 4, btns[i] == undefined !!!!
        var number = btn.getAttribute("data-num");
        console.log(number);
    });
}
<button class='btn' data-num='0'>0</button>
<button class='btn' data-num='1'>1</button>
<button class='btn' data-num='2'>2</button>
<button class='btn' data-num='3'>3</button>
junvar
  • 11,151
  • 2
  • 30
  • 46