最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to fix "Cannot read property 'getAttribute' of undefined? - Stack Overflow

programmeradmin1浏览0评论

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.

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.

Share Improve this question edited Aug 15, 2019 at 15:06 TylerH 21.1k79 gold badges79 silver badges114 bronze badges asked Aug 15, 2019 at 14:48 Michael MeachamMichael Meacham 211 silver badge2 bronze badges 3
  • Possible duplicate of JavaScript closure inside loops – simple practical example – Heretic Monkey Commented Aug 15, 2019 at 14:51
  • on which iteration does it fail in the loop? – SomethingCool Commented Aug 15, 2019 at 14:53
  • @JuanDM, you may be misunderstanding how < and [].length works. – junvar Commented Aug 15, 2019 at 14:55
Add a ment  | 

3 Answers 3

Reset to default 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!!

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>

I came to this page with exactly the same problem !! After trying the suggestions and getting the same error, I re-checked the data-items I was using. Because I was working on a diary project, mine had dates:

    <pre>
        <li data-date="#01/01/1900">The Past</li>
        <li data-date="#01/04/1994">Apr '94</li>
        <li data-date="#01/10/1996" class="selected">Oct '96</li>
        <li data-date="#01/09/2005">Sep '05</li>
    </pre>

These were designed to align with a second list containing further information:

    <pre>
        <li id="01/01/1900">
        <li id="01/04/1994">
        <li id="01/10/1996" class="selected">
        <li id="01/09/2005">
    </pre>

I knew that I had the correct selectors and eventListener, as I had used similar code previously:

    <pre>
            const events = document.querySelectorAll(".events ol li");

            events.forEach((event) => {
                event.addEventListener("click", () => {
  
                    const eventDate = this.getAttribute("data-date");
                    const eventInfo = document.querySelector(eventDate);

                    console.log(eventDate);
                    console.log(eventInfo);
                });
            });
    </pre>

But the error persisted !!

It was only when I tried changing the data-date and ID items to simply "first", "second", "third", "fourth" etc that the errors disappeared, and my code worked as expected.

In conclusion: remove any punctuation from your IDs and data-items.

发布评论

评论列表(0)

  1. 暂无评论