JavaScript:将元素添加到DOM并继承事件处理程序

时间:2018-01-26 19:30:44

标签: javascript arrays ajax javascript-events event-handling

我在<textarea>内有<button><form>。提交后,我致电e.preventDefault()并通过AJAX提交表单。在那里,我返回查询并PREPEND查看此列表顶部<div>内的信息。

此外,我已经为每个项目提供了删除功能,这在客户端是即时的,但也通过AJAX提交表单以完全删除。这有点工作。

我能够

  • 有一个空白屏幕(没有添加任何项目),创建一个并删除它没有问题
  • 有空白屏幕,添加两个项目,删除最新项目没有问题但删除第二个项目(这是第一个或最旧的项目)返回错误。它试图删除自己和最新的项目。因此,如果我有三个,它将删除自己和最新的,只留下项目#2。添加的项目越多,情况就越糟。

我需要做什么

  • 让新的Prepended元素继承事件处理程序
  • 仅删除所选项目

代码说明

当用户加载页面时,会立即查询存储在数据库中的项目并将其添加到屏幕中。

继续,在第一个代码示例中找到const delPostFunc。这是一个立即调用的匿名函数,以确保最初添加到屏幕的任何项目都被分配了click事件处理程序。

当用户通过submitPostBtn.addEventListener('click', e => {提交新项目时,在第一个示例的底部,会进行两次调用。第二个示例中为const submitPostAJAX,第二个示例中为const returnNewestPostAJAX。这个returnNewestPost调用会从数据库中返回一些DATA,这恰好是插入的最新项目,然后PREPENDS此项目位于列表顶部,{{1}最后调用displayPostWrapper.prepend(newPostDiv);函数以尝试将事件处理程序重新分配给新插入的项。这是因为delPostFunc();删除了应该在元素上的任何事件处理程序,或者这是我所相信的。

的JavaScript

innerHTML

这些是AJAX的承诺

// DELETE POST VARIABLES
let deletePostBtn      = document.querySelectorAll('button[name="delete_post"]');
const displayPostWrapper = document.querySelector('.col-8.pt-4');
let displayPostSection = document.querySelectorAll('.col-8.pt-4 .row');
let postID             = document.querySelectorAll('#delete-post-id');

// SUBMIT POST VARIABLES
const submitPostBtn = document.querySelector('#submit-post-button');
const submitPostID  = document.querySelector('#submit-post-id');
const submitPostContent  = document.querySelector('#submit-post-content');
const submitPostName  = document.querySelector('#submit-post-name');

// MAKING THE CALL TO DELETE THE POST
const delPostFunc = () => {
  console.log(deletePostBtn);
  deletePostBtn = document.querySelectorAll('button[name="delete_post"]');
  console.log(deletePostBtn);

  if (deletePostBtn) {  
    for (let i = 0; i < deletePostBtn.length; i++) {
      deletePostBtn[i].addEventListener('click', e => {
        e.preventDefault();
        postID = document.querySelectorAll('#delete-post-id');
        displayPostSection = document.querySelectorAll('.col-8.pt-4 .row');

        console.log(postID[i].value);


        // ${postID[i]} comes from `const postID` at the top
        deletePostPromise('http://localhost/mouthblog/ajax/delete_post.ajax.php', `id=${postID[i].value}`);

        console.log(deletePostBtn);
        displayPostSection[i].remove();
        console.log(deletePostBtn);
      });
    }
  }
}
// CALL `delPostFunc()` FOR THE INITIAL `deletePostBtn` ON SCREEN
delPostFunc();

// MAKING CALL TO SUBMIT NEW POST
if (submitPostBtn) {
  submitPostBtn.addEventListener('click', e => {
    e.preventDefault();

    // SUBMIT POST
    submitPost('http://localhost/mouthblog/ajax/submit_post.ajax.php',
      `id=${submitPostID.value}&name=${submitPostName.value}&content=${submitPostContent.value}`)
      .then(() => {
        // RETURN THAT SAME POST
        returnNewestPost('http://localhost/mouthblog/api/newest_post.php')
          .then(data => {
            // INSERT POST INTO DOM
            const newPostDiv = document.createElement('div');
            newPostDiv.setAttribute('class', 'row');
            newPostDiv.innerHTML = `
                                    <article class="col-10 offset-1">
                                      <h2 class="h2">${data.user_name}</h2>
                                      <small>${data.date_created}</small>
                                      &nbsp;
                                      &nbsp;
                                      <form action="//localhost/mouthblog/blog.php" method="POST">
                                        <button class="btn btn-danger" name="delete_post" type="submit">DELETE</button>
                                        <input id="delete-post-id" name="post_id" type="hidden" value="${data.id}">
                                      </form>
                                      <hr>
                                      <p class="lead">${data.content}</p>
                                    </article>
            `;
            console.log(`INSERTING ${data.id}`);

            displayPostWrapper.prepend(newPostDiv);

            console.log(`INSERT ${data.id} COMPLETE`);

            // GIVE THE `newPostDiv`'s `delete button` THE CLICK EVENT HANDLER
            console.log(`RUNNING delPostFunc()`);

            delPostFunc(); // BOOM!

            console.log(`delPostFunc() COMPLETE`);
          });
      });
  });
}

1 个答案:

答案 0 :(得分:0)

这个问题的最简单答案是使用Event Delegation重写脚本。

  

事件委托允许我们将单个事件侦听器附加到父元素,该元素将为匹配选择器的所有后代触发,无论这些后代现在是存在还是将来添加。

比较OP中的脚本并比较一下。重写的脚本具有更少的代码,更少的循环,更少的变量,并且更易于维护和阅读。

如果您想比较细节,事件委托会从error: implicit instantiation of undefined template 'std::__1::hash<std::__1::vector<int, std::__1::allocator<int> > >'

开始

重写JS

if (displayPostWrapper && submitPostBtn) {