首页 > 解决方案 > 每次在 Rails 中由 Vanilla Javascript 加载部分时查询选择元素

问题描述

我在具有radio buttons 或check boxes 的部分内部有一个部分。我想要做的是获取单击的单选按钮或复选框。现在,最初在页面加载时我能够获得按钮,但是当我进入下一个部分时,我无法获得新按钮。每次在单独的 js 中单击某个按钮时,如何获取新部分的按钮。如果我使用onclick内联函数radio buttoncheckbox然后正确调用该函数,但我想在单独的 js 文件中获取当前显示的元素。

我尝试使用window.addEventListener('change'). 如果我使用它,那么在第一次单击时不会调用该函数,但在随后的单击中它会调用很多次,即第二次单击该函数被调用一次,第三次单击该函数被调用两次,依此类推。

// window.addEventListener('change', () => {
window.addEventListener('DOMContentLoaded', () => {
  if (document.querySelectorAll('[name="question[answer_id]"]').length !== 0) {
    document.querySelectorAll('[name="question[answer_id]"]').forEach((questionAnswerButton) => {
      questionAnswerButton.addEventListener('click', (event) => {
        console.log(event);
        fetchCall(event.target.value);
      });
    });
  }
});

radio_button_partial.html.erb

<%= radio_button_tag 'question[answer_id]',
                                  answer.id,
                                  (user_answer == answer.id),
                                  {
                                    class: 'answer_opt',
                                    // onclick: fetchCall("<%= answer.id %>")
                                  } %>

在这里,如果我取消注释 onclick 功能,那么我将获得所需的功能。但是,我应该从单独的 js 文件中获取当前显示的单选按钮,我应该对此进行哪些更改?

标签: javascriptruby-on-railserb

解决方案


而不是将侦听器直接附加到要使用事件冒泡的元素:

document.addEventListener('click', (event) => {
  if (event.target.matches('[name="question[answer_id]"]')) {
    console.log(event);
    fetchCall(event.target.value);
  }
});

当一个事件被触发时,它会在 DOM 中冒泡,直到找到处理程序。与将事件处理程序直接附加到元素不同,这是幂等的,并且处理程序将适用于动态插入页面的元素。它还与 turbolinks 兼容。

这段代码不应该放在脚本标签或.js.erb可憎的地方,因为它会在每次执行代码时添加一个处理程序。将其放入资产管道中。

如果fetchCall进行 ajax 调用,您将需要使用去抖动技术,例如禁用输入并在解决承诺时重新启用它。

document.addEventListener('click', (event) => {
  if (event.target.matches('[name="question[answer_id]"]')) {
    console.log(event);
    // Todo refactor fetchCall so that it returns a promise
    let promise = fetchCall(event.target.value);
    event.target.disabled = true;
    promise.then((successMessage) => {
      event.target.disabled = false;
    });
  }
});

推荐阅读