每次在 Rails 中由 Vanilla Javascript 加载部分时查询 select 个元素

Query select elements everytime partial is loaded by Vanilla Javascript in Rails

我在一个部分中有一个部分,其中有 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 文件中获取当前显示的单选按钮?

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

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 调用,您将需要使用去抖动技术,例如禁用输入并在 the promise 解决后重新启用它。

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