如何让DOM /事件侦听器知道新添加的节点?

时间:2017-03-31 19:33:34

标签: javascript jquery html jquery-selectors event-delegation

TL; DR:

我使用$(..).append(node),但不考虑新添加的节点,尽管它们(据称)匹配jQuery选择器。

问题

我在下面有一些使用复选框但是模拟单选按钮行为的代码。换句话说,任何时候都只能(有效地)选择一个复选框。应该选择不超过一个。

如果您运行下面的示例并单击前3个复选框,它们将表现得像单选按钮。无论您点击多少,都只会选择一个。

但是,如果你添加点,即使理论上它也应该抓住它,新的点也不会被考虑用于JS ......

具体来说:您可以选择新添加的复选框,除了之前已选择的复选框外,还会选中该复选框。这是不正确的,因为任何时候都应该只选择1,而其他所有其他都应该被取消选择。

发生了什么,如何将新添加的节点包含在jQuery选择器中?

$(function() {

  //check first box
  $("input.duty:first").prop("checked", true);

  //clicking unchecked box should check that box
  //unchecks all others
  $(".duty").on('click', function(event) {
    $("input.duty").prop("checked", false);
    $(this).prop("checked", true);
  });

  $("#addCasePoint").on("click", function() {
    var newRowIndex = $('#newRowIndex').text();
    var template = $('#casePointTemplate').data('template');
    template = template.replace(/__index__/g, newRowIndex);
    $('#casePointsFieldset').append(template);
    $('#newRowIndex').text(++newRowIndex);
    return false;
  });

  //deletes case point
  $("#selection").on("click", ".removeCase", function() {
    var caseCount = $('#selection .casePointFieldset').length
    if (caseCount === 1) return false; //keep at least one row
    $(this).closest("fieldset").remove();
    return false;
  });
});
.casePointFieldset {
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form id="selection">
  <fieldset id="casePointsFieldset">
    <legend>Case Points</legend>
    <div id="pointFieldset">
      <fieldset class="casePointFieldset">
        <div>
          <label><span>Duty:</span> <input name="point[1]" class="duty" value="1" type="checkbox"></label>
        </div>
        <button class="removeCase">Remove</button>
      </fieldset>
      <fieldset class="casePointFieldset">
        <div>
          <label><span>Duty:</span> <input name="point[1]" class="duty" value="1" type="checkbox"></label>
        </div>
        <button class="removeCase">Remove</button>
      </fieldset>
      <fieldset class="casePointFieldset">
        <div>
          <label><span>Duty:</span> <input name="point[1]" class="duty" value="1" type="checkbox"></label>
        </div>
        <button class="removeCase">Remove</button>
      </fieldset>
    </div>
    <!-- include template -->
    <span id="casePointTemplate" data-template="<fieldset class=&quot;casePointFieldset&quot;><div><label><span>Duty:</span> <input name=&quot;point[__index__]&quot; class=&quot;duty&quot; value=&quot;1&quot; type=&quot;checkbox&quot;></label></div><button class=&quot;removeCase&quot;>Remove</button></fieldset>">
    </span>
  </fieldset>

  <button id="addCasePoint">Add Point</button>
</form>

2 个答案:

答案 0 :(得分:2)

问题是你如何绑定它们。 .click函数(或.on('click'))基本上是这样的:

  1. 查找与选择器匹配的所有当前存在的元素($('.your.selector.here')
  2. 将事件处理程序附加到那些元素
  3. 中的每一个

    请注意我提到它是如何绑定已经存在的?这意味着它不会自动绑定到新创建的。但是,您可以使用.on绑定到这些元素的父级,然后在选择器上侦听事件。我会告诉你我的意思:

    $('#addItem').click(function() {
      $('.container').append('<button class="item">Item</button>');
    });
    
    // Notice that I'm binding to the parent
    // then specifying which events from it's children
    // I want to listen to (click events from .item elements)
    $('.container').on('click', '.item', function() {
      console.log("I'm an item");
    });
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div class="container">
      <button class="item">Item</button>
    </div>
    <button id="addItem">Add New Item</button>

    如果您将on('click'更改为此类工作,那么您将没有任何问题。

答案 1 :(得分:1)

最简单的方法是将事件附加到文档中。在过去,这是使用live()方法完成的。

 $(document).on('click', '.duty', function(event) {
      $("input.duty").prop("checked", false);
      $(this).prop("checked", true);
  });