如何对动态添加的元素执行动态操作?

时间:2018-05-26 12:45:43

标签: javascript jquery html

我的目标:

  • 使用JS / Jquery
  • 动态填写'performer-payments'表
  • 对于表中的每个(动态添加的)行,其中一个数据单元格包含一个下拉框。
  • 当选择某个选项时,此下拉框应该显示另一个下拉框(在同一个单元格中)。否则,第二个下拉列表应该是不可见的。
  • 在其他地方,我通过toggleVisible函数完成隐藏/显示动态,它只是添加了由css标记的自定义类来隐藏或显示元素。

相关代码:

我要填写的表格:

<table id='performer-payments' class='performer-profile payments-table'>              
    <tr>
        <th> Period </th>                                                             
        <th> Amount </th>                                                             
        <th> Paid? </th>                                                              
    </tr>
</table>

填充表格的代码:

for (period in data['Performers'][performer]['Payments']) {
    var amount = utils.calcPerformerCut(data, performer, period);                 
    var row = "<tr>";
    row += "<td> " + period + " </td>";
    row += "<td> " + amount + " $ </td>";
    row += "<td>";
    row += "<div class='performer-profile payment-status'>";
    row += data['Performers'][performer]['Payments'][period];
    row += "</div>";
    row += "<select id='payment-status-" + performer + "-" + period + "' class='perfomer-profile hidden-onload displayNone payment-status-menu'>";
    row += "<option value='paid'>Paid</option>";
    row += "<option value='unpaid'>Unpaid</option>";
    row += "<option value='transfer'>Transfer to...</option>";
    row += "</select>";
    row += "<select id='payment-transfer-period-" + performer + "-" + period + "' class='performer-profile hidden-onload displayNone payment-period-menu'>";
    for (var i=0; i < data['Periods'].length; i++) {                              
        row += "<option value='" + period + "'>" + period + '</option>';          
    }
    row += "</select>";
    row += "</td>";
    row += "</tr>";

    $('#performer-payments').append(row);
    $('#performer-payments').on('change', {perf: performer, per: period}, function (even) {
        if (even.target.value == 'transfer') {
            utils.toggleVisible($('#payment-transfer-period-' + even.data.perf + '-' + even.data.per), true);
        } else {
            utils.toggleVisible($('#payment-transfer-period-' + even.data.perf + '-' + even.data.per), false);
        }
    });
}

供参考,切换可见性的代码:

exports.toggleVisible = function (selector, visible) {
    if (visible) {
        selector.removeClass('displayNone').addClass('displayBlock');
    } else {
        selector.removeClass('displayBlock').addClass('displayNone');
    }
}

至少有两个问题:

  • 即使在第一个选择框中选择了“转移”选项,也不会显示#payment-transfer-period -...选择框。从调试工作来看,我觉得可能是#payment-transfer-period- ..由于某种原因还不是一个有效的对象,或类似的东西。
  • (显然,真的),on-change事件被触发N次(N =周期数),因为我只是告诉程序在表中的某些内容发生变化时触发。我希望它只触发相关的下拉列表,但当我尝试将#payment-status -...作为选择器添加到.on()函数时,它使它永远不会触发。

注意:我欢迎对此提出反馈 - 我是一名经验丰富的程序员,但对HTML / JS / Jquery的经验很少。此外,我决定不使用模板进行这个项目,因为我正在尝试学习基础知识,所以如果你从看到我动态'添加行到表的方式得到胰腺炎,我道歉,但它是部分故意的。

除此之外,如果此处不清楚,请询问澄清。

编辑:以下是数据结构的相关部分:

data = {
    'Performers': {
        'Dira Klaggen': {
            'Payments': {
                'Q1': 'Paid',
                'Q2': 'Paid',
                'Q3': 'Unpaid'
            },
        },
        'Holden Bolden': {
            'Payments': {
                'Q2': 'Transferred to Q3',
                'Q3': 'Unpaid'
            }
        },
        'Manny Joe': {
            'Payments': {
                'Q1': 'Paid',
                'Q2': 'Unpaid',
                'Q3': 'Unpaid',
            }
        }
    },
    'Periods': [
        'Q1',
        'Q2',
        'Q3'
    ]
}  

2 个答案:

答案 0 :(得分:2)

您没有将change处理程序附加到右侧元素。我应该是行中的第一个select ...而不是整个table

试试这个change处理程序:

$('#performer-payments').find('#payment-status-' + performer + '-' + period).on('change', function(){
  if ($(this).val() == 'transfer') {
    $(this).next('select').show();
  } else {
    $(this).next('select').hide();
  }
});

<小时/> 第二种方法:
您可以通过使用类而不是复杂的&#34;来简化它。第一个id的唯一select

假设您使用class&#34;付款状态&#34;:

处理程序将是:

$('#performer-payments').on('change', '.payment-status', function(){
  if ($(this).val() == 'transfer') {
    $(this).next('select').show();
  } else {
    $(this).next('select').hide();
  }
});

此处理程序可能不在行追加循环中,因为它使用delegation

答案 1 :(得分:1)

通过执行以下操作来清理代码:

  1. 使用类而不是丑陋的ID。

  2. 使用data-attributes或隐藏的输入字段来保存额外信息。

  3. 使用event delegation绑定动态创建的元素。在事件处理程序内部,使用tree traversal方法根据当前元素this限制搜索范围。

  4. 让我们应用这些东西。

    像这样构建每一行。 {PLACEHOLDER}是您在代码中放置变量内容的地方。

    <tr>
        <td>{PERIOD}</td>
        <td>{AMOUNT} $ </td>
        <td>
            <div class='performer-profile payment-status'>
                {SOMETHING-RELATING-TO-PERFORMER-PAYMENT-PERIOD}
            </div>
            <!-- remove ID -->
            <!-- store performer and period in data-attributes -->
            <select class='perfomer-profile hidden-onload displayNone payment-status-menu' data-performer='{PERFORMER}' data-period='{PERIOD}'>
                <option value='paid'>Paid</option>
                <option value='unpaid'>Unpaid</option>
                <option value='transfer'>Transfer to...</option>
            </select>
            <!-- remove ID -->
            <select class='performer-profile hidden-onload displayNone payment-period-menu'>                             
                <option value='{PERIOD}'>{PERIOD}</option>
                <option value='{PERIOD}'>{PERIOD}</option>  
                <option value='{PERIOD}'>{PERIOD}</option>
                <!-- etc -->
            </select>
        </td>
    </tr>
    

    在JavaScript中,创建一个delegated event handler。请注意语法。

    $(function () {
    
        // ...
    
        for (period in data['Performers'][performer]['Payments']) {
            // build and append row
        }
    
        // create delegated event handler once and outside FOR loop
        $(document).on('change', '.payment-status-menu', function () {
            // get the current status menu
            var statusMenu = $(this);
            // find its related period menu
            var periodMenu = statusMenu.closest('tr').find('.payment-period-menu');
            // toggle its visibility
            periodMenu.toggle(this.value == 'Transfer');
    
            // of course, this could be a one-liner
            //$(this).closest('tr').find('.payment-period-menu').toggle(this.value == 'Transfer');
        });
    
    });
    

    您似乎不需要(2.)但如果您这样做,请在事件处理程序中使用statusMenu.data('performer') or statusMenu.data('period')来获取其执行者和期间值。您也可以this.dataset.performer or this.dataset.period