【问题标题】:JavaScript: Form is not operating correctly after AJAX returnsJavaScript:AJAX 返回后表单无法正常运行
【发布时间】:2018-07-05 07:20:18
【问题描述】:

我的 JS let deletePostBtn = document.querySelectorAll('button[name="delete_post"]'); 顶部定义了一个按钮列表。我正在使用let,因为我认为它需要稍后重新定义。

单击时,此按钮调用e.preventDefault() 并使用我编写的自定义AJAX(在此处的帮助下)。

加载页面,点击DELETE按钮,一切正常,根据AJAX返回的数据库查询删除元素并重新加载元素。

现在问题来了。在AJAX 返回数据并加载元素后,单击的下一个按钮就像普通表单一样,不再调用我的addEventListener。我需要它调用 addEventListener 并让它再次运行 AJAX

重要提示

现在,如果您查看脚本,您会注意到我在 get() Promise 中创建了两个 console.log()s。它嵌套在我的deletePostPromise() Promise 中。这两个console.log() 输出预期的数据。假设我有五个按钮,当点击它最初返回NodeList(5) [array of buttons],然后它会返回NodeList(4) [array of buttons]

我的猜测是我的let deletePostBtn = document.querySelectorAll('button[name="delete_post"]'); 需要稍后在脚本中重新定义,但我不确定在哪里。

JavaScript

let deletePostBtn = document.querySelectorAll('button[name="delete_post"]');

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

// MAKING THE CALL TO DELETE THE POST
if (deletePostBtn) {
  for (let i = 0; i < deletePostBtn.length; i++) {
    deletePostBtn[i].addEventListener('click', e => {
      e.preventDefault();
      console.log(deletePostBtn); // Returns 'NodeList(5) [array]'

      const displayPostWrapper = document.querySelector('.col-8.pt-4');
      const displayPostSection = document.querySelectorAll('.col-8.pt-4 .row');
      const postID = document.querySelectorAll('#delete-post-id');

      deletePostPromise('http://localhost/mouthblog/ajax/delete_post.ajax.php', `id=${postID[i].value}`)
        .then(() => {
          console.log('JUST DELETED POST');
        })
        .then(() => {
          get('http://localhost/mouthblog/api/blog.php')
            .then(data => {
              console.log(data);

              displayPostWrapper.innerHTML = '';

              data.map(x => {
                displayPostWrapper.innerHTML += `<div class="row">
                                                   <article class="col-10 offset-1">
                                                     <h2 class="h2">${x.user_name}</h2>
                                                     <small>${x.date_created}</small>
                                                     &nbsp;
                                                     &nbsp;
                                                     <form class="" 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="${x.id}">
                                                     </form>
                                                     <hr>
                                                     <p class="lead">${x.content}</p>
                                                   </article>
                                                </div>
                                                `;
              }); // map

              let deletePostBtn = document.querySelectorAll('button[name="delete_post"]');
              console.log(deletePostBtn); // Returns 'NodeList(4) [array]
            })
            .catch(error => {
              console.log(error);
            });
        }).catch(error => {
          console.log(error);
        });
    });
  }
}

【问题讨论】:

  • 一个建议 - 与其重绘所有在您删除某些内容时没有被删除的帖子,您可以删除那些删除的帖子吗?您的问题可能是由于没有在重绘的帖子删除按钮上设置事件处理程序,因此要修复 1)不要重绘帖子或 2)在重绘后将事件处理程序添加到所有新的删除按钮。
  • @James 你如何建议我为每个按钮添加一个事件处理程序,因为它们是动态创建的。将onclick= 添加到按钮本身以调用它?

标签: javascript ajax variables dom


【解决方案1】:

如果您使用事件委托来处理删除按钮的点击,您只需要设置一个侦听器,并且您可以添加任意数量的新删除按钮,它们都会起作用。

我已将删除按钮处理程序的主要内容移至其自己的函数 (doStuff)。我将 displayPostWrapper 的声明移到处理程序之外,以便我们可以在其上捕获单击事件,检查单击是否发生在删除按钮上,如果是,则调用 doStuff。

我解决了您的 post_id 由具有重复 ID 的元素设置的问题 - 我完全摆脱了该 ID,它现在使用 querySelector 来查找正确的元素。

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

displayPostWrapper.addEventListener("click", function (e) {
  // the parent was clicked - lets see if the click was actually on a delete button
  if(e.target && e.target.nodeName == "BUTTON" && e.target.name == "delete_post") {
    doStuff.call(e.target, e);
  }
});

function doStuff(e) {
  e.preventDefault();
  console.log(deletePostBtn); // Returns 'NodeList(5) [array]'

  const displayPostSection = document.querySelectorAll('.col-8.pt-4 .row');
  const postID = this.form.querySelector('input[name=post_id]').value;

  deletePostPromise('http://localhost/mouthblog/ajax/delete_post.ajax.php', `id=${postID}`)
    .then(() => {
      console.log('JUST DELETED POST');
    })
    .then(() => {
      get('http://localhost/mouthblog/api/blog.php')
        .then(data => {
          console.log(data);

          displayPostWrapper.innerHTML = '';

          data.map(x => {
            displayPostWrapper.innerHTML += `<div class="row">
                                               <article class="col-10 offset-1">
                                                 <h2 class="h2">${x.user_name}</h2>
                                                 <small>${x.date_created}</small>
                                                 &nbsp;
                                                 &nbsp;
                                                 <form class="" method="POST">
                                                   <button class="btn btn-danger" name="delete_post" type="submit">DELETE</button>
                                                   <input name="post_id" type="hidden" value="${x.id}">
                                                 </form>
                                                 <hr>
                                                 <p class="lead">${x.content}</p>
                                               </article>
                                            </div>
                                            `;
          }); // map

          let deletePostBtn = document.querySelectorAll('button[name="delete_post"]');
          console.log(deletePostBtn); // Returns 'NodeList(4) [array]
        })
        .catch(error => {
          console.log(error);
        });
    }).catch(error => {
      console.log(error);
    });
}

【讨论】:

  • 嗯...虽然我很欣赏您的回复,但您所写的内容现在始终以正常形式提交。我认为doStuff() 函数被完全忽略了。
  • 糟糕,我忘记了 .nodename 属性总是以大写形式返回名称。已修复 - 再试一次!
  • 谢谢,但我走了另一条路。如果您仍然想提供帮助,可以在这里查看我的最新问题stackoverflow.com/questions/48468289/…。顺便说一句,感谢您的帮助!
  • 嘿,我很高兴你决定从 DOM 中删除元素并完成它,这是一个更清洁的解决方案。
【解决方案2】:

所以我找到了一种不同的方法来解决这个问题,我将把它贴在这里作为答案。它可以帮助某人。

@James 在 OP cmets 中建议

一个建议 - 而不是重绘所有没有得到的帖子 当你删除某些东西时删除,你能把那个删除吗? 做过?您的问题可能是由于没有设置事件处理程序 重绘后删除按钮,因此要修复 1) 不要重绘 帖子或 2) 将事件处理程序添加到所有新的删除按钮 重绘。

考虑到这个网络应用程序的未来,我选择了完全从DOM 中删除元素的路线。使用内置的 JavaScript 方法 - .remove() 不仅将其从 DOM 中删除,而且用户不必等待 AJAX 从数据库中返回数据。此外,代码更简洁,对开发人员友好,而且更易于使用。

通过删除不必要的 AJAX 调用,我不仅加快了应用程序的运行速度,还删除了 56 行代码。

JS

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

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

// MAKING THE CALL TO DELETE THE POST
if (deletePostBtn) {
  for (let i = 0; i < deletePostBtn.length; i++) {
    deletePostBtn[i].addEventListener('click', e => {
      e.preventDefault();
      console.log(deletePostBtn);

      displayPostSection[i].remove();

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

【讨论】:

    【解决方案3】:

    在 ajax 响应处理程序中再次将事件侦听器添加到您的元素。因为您删除了那些附加了事件侦听器的元素。

    【讨论】:

    • 您能说得更具体些吗?我需要为新生成的按钮编写另一个 .addEventListener 吗?具体在哪里?我需要重新定义按钮数组吗?
    • 在resolve方法看来resolve(JSON.parse(xhttp.response));
    猜你喜欢
    • 1970-01-01
    • 2015-11-10
    • 1970-01-01
    • 1970-01-01
    • 2021-02-10
    • 1970-01-01
    • 1970-01-01
    • 2014-07-01
    • 1970-01-01
    相关资源
    最近更新 更多