如何将javascript事件处理程序附加到在javascript中创建的这些元素

时间:2014-10-26 21:16:28

标签: javascript jquery

背景

我不是那里最热门的jQuery家伙,而且我试图在下面的代码中删除重复的工作。虽然性能开销可能很小并且可以忽略不计 - 但这更像是一个不想写几次做同样事情的糟糕代码的情况。

基本上我有一个简单的发票表单,用户也可以添加多个项目。

表单最初有4个输入:项目名称,项目价格,项目数量和总计

  • 只要“价格”或“数量”字段触发更改事件
  • ,就会计算总数

问题 - 部分解决(见更新)

用户可以为第二个(或第三个,第四个,第五个等等)项添加额外的一行输入

  • 将事件处理程序附加到pricequantity字段的现有javascript已经运行,因此不会将侦听器附加到新添加的输入行。

解决方案?

目前,我已经删除了一些可怕的东西,在添加新的输入行后,我将一个事件监听器重新附加到所有输入字段。

我觉得很酷,如果你对你的工作质量不感到骄傲,但如果发票是20个项目,我真的需要在已经拥有的19行上添加第20项行循环附加的侦听器,再次附加它们,然后将侦听器附加到新行。我希望不会。

我已经设法定位新添加的输入行来擦除克隆输入中的值 - 所以我想只是定位新的输入字段并附加听众 - 但是我是得到正确的两个和八个因为理想情况下我喜欢这样做

  1. 克隆输入行
  2. 清除值
  3. 附加听众
  4. 添加到DOM
  5. 我目前正在做的事情是什么感觉怪诞

    1. 克隆行
    2. 将行添加到DOM
    3. 选择新添加的行并擦除值
    4. 选择新添加的数量字段并附加监听器
    5. 选择新添加的价格字段并附加监听器
    6. 选择新添加的总计字段并附加监听器(以更新发票总额)
    7. 下面的代码,让你嘲笑,然后希望对我表示同情并提供一个更简洁的解决方案,或者至少建议如何编写我自己更好的版本。

      /** Add additional item lines */
      $('#add-item').click(function(e){
          e.preventDefault();
          /** clone first line and insert it */
          $('.input-row:first').clone().insertAfter('.input-row:last');
          /** clear the newly inserted inputs of values */
          $(':input', '.input-row:last').val("");
          /** ensure all item price and qty inputs have events attached to their change value */
          $('input[name="item_qty[]"],input[name="item_price[]"]').on("change",function () {
              var $container = $(this).closest('.form-group');
              qty = Number($('input[name="item_qty[]"]',$container).val())||0,
              price = Number($('input[name="item_price[]"]',$container).val())||0;
              $('input[name="item_total[]"]',$container).val(qty * price);
              $('input[name="item_total[]"]',$container).change();
          });
          /** Sum inputs for invoice total */
          $('input[name="item_total[]"').change(function() {
              var total = 0;
              $.each($("[name='item_total[]']"), function(index, value) {
                  total += parseFloat($(this).val());
              });
              $("#total").val(total);
          });
      });
      

      更新

      因此,通过利用事件委托,事件在dom上传播(或冒泡) - 谢谢你们!在新的父div中的一个输入发生变化时,我已经重新计算了发票总额

      <div id="invoice-items">
          <input name /> <input quantity /> <input price /> <input total />
          <input name /> <input quantity /> <input price /> <input total />
          <input name /> <input quantity /> <input price /> <input total />
          ...
      </div>
      
      /** if any input rows change update the invoice total */
      $('#invoice-items').on('change', 'input', function(event){
          var total = 0;
          $.each($("[name='item_total[]']"), function(index, value) {
              total += parseFloat($(this).val());
          });
          $("#total").val(total);
      });
      

      问题我离开......

      我仍然坚持如何更新<input total />以反映对该特定行的更改。我在我的新jQuery片段中某处猜测我需要确定哪个字段已更改并更新同一行的总数?

      这就是我目前如何将更改侦听器附加到第一行/现有输入行以填充行总数

      /** calculate item total */
        $('input[name="item_qty[]"],input[name="item_price[]"]').on("change", function () {
          var $container = $(this).closest('.form-group');
          qty = Number($('input[name="item_qty[]"]',$container).val())||0,
          price = Number($('input[name="item_price[]"]',$container).val())||0;
      
          $('input[name="item_total[]"]',$container).val(qty * price);
          $('input[name="item_total[]"]',$container).change();
        });
      

      我想我还需要一些方法来在添加一行之后运行此代码,或者遵循清除事件委派路由 - 某种方式只针对更改事件所在行的item_total[]发生 ?也许我可以捕获触发更改事件的元素的特定索引 - 并仅更新该索引处的item_total[]

      在这里大声思考,我想如果我捕获事件并遍历所有输入,直到我发现与该事件被触发的元素匹配的元素,然后我可以获取名为{{的下一个表单输入1}}并更新它? - 让我们去检查一下。

      更新

      所以我可以捕捉到这个事件 - 快乐的日子:)

      invoice_total[]

      因此,我仍然不知道我已更新了哪些event.currentTarget.attributes.name.nodeValue == 'item_qty[]' 元素,因此我不知道要更新哪个item_qty[]元素。

      有人建议吗?!?

1 个答案:

答案 0 :(得分:3)

你想要包装元素

<div>
    <input />
    <input />
</div>

$('div').on('change', 'input', function(){
    // your magic here
});

这将适用于现在在场的两个人,以及新的元素。为什么?简单地说:
您将事件绑定到存在的元素。你创建一个新的,改变它,但从未将事件绑定到新元素。事件在树上冒泡,没有什么可以抓住它。

我的代码doest绑定到元素本身,告诉它在input上听取它的变化。新的元素进来,你改变它们,没有任何事情发生,所以它在树上冒泡 这是最大的区别:这次我们告诉现有元素现在做点什么。