在循环中添加addEventListener()仅适用于最后一个按钮

时间:2016-04-29 19:31:10

标签: javascript arrays json addeventlistener

我从dynamodb获取了一个json数组,并在遍历它时向一个按钮添加了一个addEventListener()。但只有最后一个按钮才能响应。

在SO上已经asked before,这是谷歌的第一次点击所以我改变了循环以使用闭包。但我仍然无法将addEventListener()附加到最后一个按钮以外的其他位置。

我最初尝试过这个:

for (var i = 0; i < array_length; ++i) {
    (function(j) {
        var obj = data.Items[j];

        adiv.innerHTML = adiv.innerHTML + "<div class='row'><div class='center-div six columns'>" + obj.Event + ", " + obj.Location + "</div></div>";
        adiv.innerHTML = adiv.innerHTML + "<div class='row'><div class='center-div six columns'>" + obj.Date + ", " + obj.Time + "</div></div>";
        adiv.innerHTML = adiv.innerHTML + "<div class='row'><div class='center-div six columns'><button id='yay_button_" + i + "' class='button-primary'>Deltag</button></div></div>";

        var elem = document.getElementById('yay_button_' + j);
        elem.addEventListener('click', function() {
            alert('id: ' + j);
        });
    })(i);
}

然后是这个较短的版本:

(function(j) {
    document.getElementById('yay_button_' + j).addEventListener('click', function() {
        alert('id: ' + j);
    });
}(i));

我试过的另一个variant是使用new创建一个按钮:

function Button(id, number) {
    document.getElementById(id + number).addEventListener('click', function() {
        alert('click: ' + id + number);
    });
}

new Button('yay_button_', i);

我在el capitan上尝试了safari和chrome,而控制台没有错误。当我检查它时,按钮具有正确的id,yay_button_0和_1。

2 个答案:

答案 0 :(得分:3)

主要问题是每次迭代时都会重新定义adiv 的HTML 。这意味着您已经绑定到adiv的子元素的任何事件处理程序在您执行adviv.innerHTML = ...时都会丢失。虽然您分配了相同的HTML加上一些新的HTML,但您不能分配先前定义的事件处理程序。所以他们迷路了。

只有在最后一次迭代时分配的事件处理程序才会以这种方式销毁。

解决方案

快速解决方案是首先循环创建所有HTML,然后执行单独的循环来分配事件处理程序:

// First add all the new content:
var html = adiv.innerHTML;
for (var i = 0; i < array_length; ++i) {
    var obj = data.Items[i];

    html += "<div class='row'><div class='center-div six columns'>" + obj.Event + ", " + obj.Location + "</div></div>";
    html += "<div class='row'><div class='center-div six columns'>" + obj.Date + ", " + obj.Time + "</div></div>";
    html += "<div class='row'><div class='center-div six columns'><button id='yay_button_" + i + "' class='button-primary'>Deltag</button></div></div>";
}
adiv.innerHTML = html;

// Now bind the event handlers
// By using "let" instead of "var" the right value is retained
// in the handlers
for (let i = 0; i < array_length; ++i) {
    var elem = document.getElementById('yay_button_' + i);
    elem.addEventListener('click', function() {
        alert('id: ' + i);
    });
}

如果您的浏览器不支持ES2015(适用于let),那么您可以使用bind

for (var i = 0; i < array_length; ++i) {
    var elem = document.getElementById('yay_button_' + i);
    elem.addEventListener('click', function(i) {
        alert('id: ' + i);
    }.bind(null, i));
}

答案 1 :(得分:0)

来自trincot的善意建议我遍历阵列两次。首先生成html然后应用addEventListener()。第二次使用闭包来包含对addEventListener()的调用。

for (var i = 0; i < array_length; ++i) {
    var obj = data.Items[i];

    adiv.innerHTML = adiv.innerHTML + "<div class='row'><div class='center-div six columns'>" + obj.Event + ", " + obj.Location + "</div></div>";
    adiv.innerHTML = adiv.innerHTML + "<div class='row'><div class='center-div six columns'>" + obj.Date + ", " + obj.Time + "</div></div>";
    adiv.innerHTML = adiv.innerHTML + "<div class='row'><div class='center-div six columns'><button id='yay_button_" + i + "' class='button-primary'>Deltag</button></div></div>";

}

for (var i = 0; i < array_length; ++i) {
    var obj = data.Items[i];
    (function(j, event) {
        document.getElementById('yay_button_' + j).addEventListener('click', function() {
            alert('id: ' + j + ', ' + event);
        });
    }(i, obj.Event));
}