JavaScript:将元素添加到DOM并继承事件处理程序 [英] JavaScript: Prepend element to DOM and inherit event handler

查看:79
本文介绍了JavaScript:将元素添加到DOM并继承事件处理程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在< textarea> 和一个< button> ><形式> 。提交后,我调用 e.preventDefault()并通过 AJAX 提交表单。从那里我返回查询和 PREPEND ,在此列表顶部的< div> 内的信息。

I have a <textarea> and a <button> inside of a <form>. When submitted, I call e.preventDefault() and submit the form via AJAX. From there I return the query and PREPEND at information inside of a <div> at the top of this list.

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

Also, I have given each item the ability to be deleted, which is instant on the client side but also submits a form via AJAX to be completely removed. This is sort of working.


  • 留空屏幕(没有添加项目),创建一个并删除它没有问题

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


  • 让新的Prepended元素继承事件处理程序

  • 仅删除所选项目

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

When the user loads the page, items that are stored in the database are immediately queried and added to the screen.

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

Go ahead and find const delPostFunc in the first code example. This is an anonymous function that is called immediately, to ensure that any items that are initially added to the screen are assigned the click event handler.

当用户通过 submitPostBtn.addEventListener('click',e => {)提交新项目时,在第一个示例的底部,两个调用。第二个例子中有一个到 const submitPost AJAX ,而 const在第二个例子中,returnNewestPost AJAX 。这个 returnNewestPost 调用返回一些 DATA 来自数据库,恰好是插入的最新项目,然后 PREPENDS 此项目位于列表顶部, displayPostWrapper.prepend(newPostDiv); 并最终调用 delPostFunc(); 函数以尝试重新分配事件处理新插入的项目。这是因为 innerHTML 删除了应该在的所有事件处理程序元素,或者这就是我所相信的。

When a user submits a new item via submitPostBtn.addEventListener('click', e => {, at the bottom of the first example, two calls are made. One to const submitPost, AJAX in the second example, and const returnNewestPost, AJAX in the second example. This returnNewestPost call returns some DATA from the database, which just so happens to be the newest item inserted, and then it PREPENDS this item to the top of the list, displayPostWrapper.prepend(newPostDiv); and finally calls the delPostFunc(); function in an attempt to reassign the event handler to newly inserted items. This is because innerHTML removes any event handlers that are supposed to be on an element, or that is what I am lead to believe.

// 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`);
          });
      });
  });
}



这些是AJAX的承诺,只需加入



These are the promises for the AJAX just incase

// GET REQUEST TO RETRIEVE EVERY POST
const get = (url) => {
  return new Promise((resolve, reject) => {
    const xhttp = new XMLHttpRequest();

    xhttp.open('GET', url, true);

    xhttp.onload = () => {
      if (xhttp.status == 200) {
        resolve(JSON.parse(xhttp.response));
      } else {
        reject(xhttp.statusText);
      }
    };

    xhttp.onerror = () => {
      reject(xhttp.statusText);
    };

    xhttp.send();
  });
}

// DELETE SPECIFIC POST
const deletePostPromise = (url, postID) => {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();

    xhr.open('POST', url, true);

    xhr.onload = () => {
      if (xhr.status == 200) {
        console.log('if (xhr.status == 200)');
        resolve();
      } else {
        reject(xhr.statusText);
      }
    };

    xhr.onerror = () => {
      reject(xhr.statusText);
    };

    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    xhr.send(postID);
  });
}

// SUBMIT A NEW POST
const submitPost = (url, user_id, user_name, content) => {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();

    xhr.open('POST', url, true);

    xhr.onload = () => {
      if (xhr.status == 200) {
        console.log('resolving');
        resolve();
      } else {
        reject(xhr.statusText);
      }
    };

    xhr.onerror = () => {
      reject(xhr.statusText);
    };

    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    xhr.send(user_id, user_name, content);
  });
};

// RETURN THE NEWEST BLOG POST
const returnNewestPost = (url) => {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();

    xhr.open('GET', url, true);

    xhr.onload = () => {
      if (xhr.status == 200) {
        console.log('resolving');
        resolve(JSON.parse(xhr.response));
      } else {
        reject(xhr.statusText);
      }
    };

    xhr.onerror = () => {
      reject(xhr.statusText);
    };

    xhr.send();
  });
}


推荐答案

这个问题最简单的答案是使用活动委派重写脚本。

The simplest answer to this question is to rewrite the script using Event Delegation.

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

Event delegation allows us to attach a single event listener, to a parent element, that will fire for all descendants matching a selector, whether those descendants exist now or are added in the future.

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

Compare the script from the OP and compare this one. The rewritten script has less code, less loops, less variables and is a lot easier to maintain and read through.

如果您想比较细节,事件委托开始于的行if(displayPostWrapper&& submitPostBtn){

If you would like to compare specifics, event delegation starts on the line with if (displayPostWrapper && submitPostBtn) {

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');

const displayPostWrapper = document.querySelector('.col-8.pt-4');

// GET REQUEST TO RETRIEVE EVERY POST
const get = (url) => {
  return new Promise((resolve, reject) => {
    const xhttp = new XMLHttpRequest();

    xhttp.open('GET', url, true);

    xhttp.onload = () => {
      if (xhttp.status == 200) {
        resolve(JSON.parse(xhttp.response));
      } else {
        reject(xhttp.statusText);
      }
    };

    xhttp.onerror = () => {
      reject(xhttp.statusText);
    };

    xhttp.send();
  });
}

// DELETE SPECIFIC POST
const deletePostPromise = (url, postID) => {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();

    xhr.open('POST', url, true);

    xhr.onload = () => {
      if (xhr.status == 200) {
        console.log('if (xhr.status == 200)');
        resolve();
      } else {
        reject(xhr.statusText);
      }
    };

    xhr.onerror = () => {
      reject(xhr.statusText);
    };

    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    xhr.send(postID);
  });
}

// SUBMIT A NEW POST
const submitPost = (url, user_id, user_name, content) => {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();

    xhr.open('POST', url, true);

    xhr.onload = () => {
      if (xhr.status == 200) {
        console.log('resolving');
        resolve();
      } else {
        reject(xhr.statusText);
      }
    };

    xhr.onerror = () => {
      reject(xhr.statusText);
    };

    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    xhr.send(user_id, user_name, content);
  });
};

// RETURN THE NEWEST BLOG POST
const returnNewestPost = (url) => {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();

    xhr.open('GET', url, true);

    xhr.onload = () => {
      if (xhr.status == 200) {
        console.log('resolving');
        resolve(JSON.parse(xhr.response));
      } else {
        reject(xhr.statusText);
      }
    };

    xhr.onerror = () => {
      reject(xhr.statusText);
    };

    xhr.send();
  });
}

// MAKING THE CALL TO DELETE THE POST
if (displayPostWrapper && submitPostBtn) {
  displayPostWrapper.addEventListener('click', e => {
    if (e.target && e.target.nodeName == 'BUTTON') {
      e.preventDefault();

      const row    = e.target.parentElement.parentElement.parentElement;
      const form   = e.target.parentElement;
      const postID = e.target.parentElement.childNodes[3].value;

      deletePostPromise('http://localhost/mouthblog/ajax/delete_post.ajax.php', `id=${postID}`);

      row.remove();
    } // if
  }); // click event

  submitPostBtn.addEventListener('click', e => {
    e.preventDefault();

    submitPost('http://localhost/mouthblog/ajax/submit_post.ajax.php',
      `id=${submitPostID.value}&name=${submitPostName.value}&content=${submitPostContent.value}`)
    .then(() => {
      returnNewestPost('http://localhost/mouthblog/api/newest_post.php')
        .then(data => {
          console.log(data);

          const newPost = document.createElement('div');

          newPost.setAttribute('class', 'row');
          newPost.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>
          `;

          displayPostWrapper.prepend(newPost);
        }) // then
    }) // then
  }); // click event
} // if

这篇关于JavaScript:将元素添加到DOM并继承事件处理程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆