[英]Add onclick event listeners to multiple buttons with Handlebar.js templates, only the last one is effective
I'm writing a web app as a homework project that uses websocket to receive messages from a server and display them on html using handlebars.js.我正在编写一个 web 应用程序作为家庭作业项目,它使用 websocket 从服务器接收消息并使用 handlebars.js 在 html 上显示它们。
I'm trying to implement the function of deleting a message using the following code:我正在尝试使用以下代码实现删除消息的 function:
document.addEventListener('DOMContentLoaded', () => {
...
let message_container = document.querySelector("#message_container");
const message_template = Handlebars.compile(document.querySelector("#message_template").innerHTML);
const delete_button_template = Handlebars.compile(document.querySelector("#delete_button_template").innerHTML);
function addDeleteButton(id) {
let con = delete_button_template({"message_id": id}); //line #1
document.querySelector("#content_" + id).innerHTML += con;
document.querySelector("#delete_button_" + id).onclick = function () {
const msg_id = event.target.dataset.message_id;
const msg = document.querySelector("#message_" + msg_id);
const blank = document.querySelector("#message_" + msg_id + "_newline");
msg.parentElement.removeChild(msg);
blank.parentElement.removeChild(blank);
}
}
The function for adding the message to the DOM is simple:用于将消息添加到 DOM 的 function 很简单:
function newMessage(i) {
let msg = message_template({
"message_id": i.message_id,
"username": ...,
"timestamp": ...,
"content": ...
});
message_container.innerHTML += msg;
addDeleteButton(i.message_id);
}
The handlebars.js Template for the delete button is plugged into HTML as following:删除按钮的 handlebars.js 模板插入到 HTML 中,如下所示:
<button id="delete_button_{{ message_id }}" data-message_id="{{ message_id }}" class="btn btn-primary">
Delete
</button>
However, every time I add a new message (including the delete button) to the DOM, all previous buttons lose their onclick() event listeners.但是,每次我向 DOM 添加新消息(包括删除按钮)时,所有以前的按钮都会失去其 onclick() 事件侦听器。 A chrome inspector shows this clearly and it happens at line #1: chrome 检查器清楚地显示了这一点,它发生在第 1 行:
The 4th button has an event listener registered.第 4 个按钮注册了一个事件侦听器。
Adding the 5th button添加第 5 个按钮
The onclick event of the 4th button disappeared.第4个按钮的onclick事件消失了。
A clear workaround is to embed the onclick call into the html attribute.一个明确的解决方法是将 onclick 调用嵌入到 html 属性中。 But why can't I register the event listeners like the given code?但是为什么我不能像给定的代码一样注册事件监听器呢?
The problem is with the following line:问题出在以下行:
message_container.innerHTML += msg;
We are using Handlebars to produce a new string of HTML which we are storing to the msg
variable.我们正在使用 Handlebars 生成一个新的 HTML 字符串,我们将其存储到msg
变量中。 We then want to append that new HTML to the #message_container
DOM element.然后我们要将append那个新的 HTML 放到#message_container
DOM 元素中。
However, message_container.innerHTML += msg
does not simply append our new HTML to the #message_container
, instead, it replaces all of the descendant DOM nodes of #message_container
!然而, message_container.innerHTML += msg
并不仅仅是append 我们新的 HTML 到#message_container
,而是替换了#message_container
的所有后代 DOM 节点!
A breakdown of what happens is:发生的事情的细分是:
#message_container
in the DOM, stringified into an HTML string.我们在 DOM 中获得#message_container
的后代节点,将其字符串化为 HTML 字符串。msg
is concatenated onto the end of this new HTML string. msg
连接到这个新的 HTML 字符串的末尾。innerHTML
of #message_container
.新的 HTML 字符串替换了#message_container
的innerHTML
。 The important part here is the replacement .这里的重要部分是替换。 When the innerHTML
of #message_container
is replaced, all of its descendant nodes are replaced .当#message_container
的innerHTML
被替换时,它的所有后代节点都会被替换。 So all of the <button>
s that you have previously attached onclick
listeners to have been removed from the DOM.因此,您之前附加的所有<button>
已从 DOM 中删除onclick
侦听器。
One way to prevent replacing all the children of #message_container
each time we want to add a <button>
would be to use the Node.appendChild()
API .每次我们想要添加<button>
时,防止替换#message_container
的所有子项的一种方法是使用Node.appendChild()
API 。 The resultant code would look like:结果代码如下所示:
// message_container.innerHTML += msg; // TODO: Replace this line with the below.
const node = document.createElement('div');
node.innerHTML = msg;
message_container.appendChild(node);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.