JavaScript 添加行到 HTML 表格并递增 ID

6
这是我在本站的第一篇帖子,希望您能给我留个面子。我正在尝试创建一个HTML/PHP表单,并使用一小段JavaScript在单击按钮时添加额外的行,并为两个字段增加ID。
按钮可以添加行,但似乎无法增加ID,只是使用与上一行相同的ID。希望有人能提供帮助?

$(window).load(function(){
        var table = $('#productanddates')[0];

    var newIDSuffix = 2;
    $(table).delegate('#button2', 'click', function () {
        var thisRow = $(this).closest('tr')[0];

        var cloned = $(thisRow).clone();
        cloned.find('input, select').each(function () {
            var id = $(this).attr('id');
            id = id.substring(0, id.length - 1) + newIDSuffix;
            $(this).attr('id', id);
        });

        cloned.insertAfter(thisRow).find('input:date').val('');

        newIDSuffix++;
    });
});  
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="blue-bar ta-l">
    <div class="container">
        <h1>Submit Your Insurance Renewal Date(s)</h1>
    </div>
</div>
<div class="grey-bar">
    <div class="container">
        <div class="rounded-box">
            <div>
                <label for="name">Name</label>
                <input type="text" id="name" name="name" autocomplete="off" required />
            </div>
            <div>
                <label for="name">Renewal Dates</label>
            </div>
            <table width="100%" border="0" cellspacing="0" cellpadding="5" id="productanddates" class="border">
                    <tr>
                        <td>
                            <select name="insurance_type1" id="insurance_type1">
                                <option></option>
                                <option>Car</option>
                                <option>Home</option>
                                <option>Van</option>
                                <option>Business</option>
                                <option>GAP</option>
                                <option>Travel</option>
                            </select>
                        </td>
                        <td>
                            <input type="date" name="renewal_date1" id="renewal_date1" />
                        </td>
                        <td>
                            <input type="button" name="button2" id="button2" value="+" />
                        </td>
                    </tr>
            </table>
            <div>
                <label for="telephone_number">Contact Number</label>
                <input type="tel" id="telephone_number" name="telephone_number" pattern="\d{11}" autocomplete="off" required />
            </div>
            <div>
                <label for="email">Email Address</label>
                <input type="email" id="email" name="email" autocomplete="off" required />
            </div>
            <div>
                <input name="submit" type="submit" value="Submit" class="btn">
            </div>
        </div>


1
对于像这样的动态HTML,最好学习如何使用类和DOM遍历,而不必担心需要ID。展示依赖于ID的代码。 - charlietfl
似乎在这个jsFiddle中有效 - http://jsfiddle.net/g7116c49/ ,只需将 .find('input:date') 更改为 .find('input.date') 并在日期输入中添加 class="date" - Sean
你尝试过将 newIDSuffix 的声明放在全局 JavaScript 中而不是 $(window).load 函数中吗? - yW0K5o
2
@charlietfl - 我不会阻止人们在表单元素中使用id属性。不仅将标签与每个输入相关联是最佳实践,通过将标签的for属性与输入的id匹配,对于任何类型的可访问性支持(例如屏幕阅读器)来说绝对必要。 - talemyn
1
@talemyn 理解你关于可访问性方面的观点,但是通常学习如何使用 DOM 的人往往过度依赖 ID 作为访问元素的最佳方式,而实际上这可能会导致额外的复杂性。 - charlietfl
显示剩余2条评论
3个回答

2
cloned.insertAfter(thisRow).find('input:date').val('');

这行不正确。它会抛出“无效选择器”错误。
你需要将其更改为:
cloned.insertAfter(thisRow).find('input[type="date"]').val('');

jQuery实际上支持选择器中的:INPUT-TYPE格式,但不支持新的HTML5输入类型(尚未支持):因此,现在使用input[type="date"]是选择具有HTML5类型的元素的正确方法。请注意值周围的引号。如果您想选择具有特定值的属性,请使用此方法。
CSS选择器的选择器概述在这里:W3schools
由于此行代码出错,因此脚本停止在该行之前,导致newIDSuffix从未得到更新。
“@Charlietfl提出了一个关于学习更多类和DOM遍历的有效观点,然而这并不能解决这个代码的问题,也不能解释为什么你的代码不起作用。尽管如此,这是一个很好的提示。”

@talemyn,感谢您的更新。我已经根据您的评论更新了我的答案,使其在技术上是正确的。 - Mouser

1

我已经尝试着整理了一份更为清晰的代码,以实现你所需要的功能。下面是主要更新:

  1. 将按钮idname从"button2"更改为"button1" - 我假设您希望在每行输入中保持索引同步。
  2. $(window).load(function() {更改为$("document").ready(function() { - 两者都可以使用,但前者会等到所有图像都加载完成后才执行,而后者会在DOM构建完成后立即执行。除非您真的想先加载图像,否则我建议使用$("document").ready(),以便更快地触发代码。
  3. 删除[0]引用 - 在jQuery选择器集合后使用[0]的主要原因是引用所选jQuery元素的DOM版本,以便在其上使用“纯”JavaScript方法。在所有情况下,您都重新包装了变量$(...),这只是将DOM元素转换回jQuery对象,因此不需要那个额外的步骤。
  4. .delegate()方法更改为.on() - 如Howard Renollet所指出的那样,这是现代版本jQuery中要使用的正确方法。请注意,在on中,“事件”和“目标”参数已与delegate中的位置交换。
  5. 将事件目标从#button2更改为:button - 这将确保新行中的所有按钮都可以添加其他行,而不仅仅是第一行。
  6. clone目标从点击的行更改为表格中的最后一行 - 这将有助于保持行编号的一致性和升序。克隆的行始终是最后一行,无论单击哪个行,新行始终会在其后放置。
  7. 更改索引,以使用最后一行的索引作为新行的基础,并使用正则表达式来确定它 - 现在表格已经排序,您始终可以指望最后一行具有最高的索引。通过使用正则表达式/^(.+)(\d+)$/i,您可以将索引值分割为“索引之前的所有内容”和“索引(即一个或多个数字,在值的结尾处)”。然后,您只需将索引增加1并重新附加它,即可得到新值。使用正则表达式方法还允许您轻松适应,如果有超过9行(即双位数索引)。
  8. 更新每个输入的idname属性 - 我假设您希望每个单独元素的idname属性与初始行相同,并且您只在代码中更新了id,这将导致发送数据时出现问题。
  9. $("input:date")更改为$("input[type='date']) - 如Mouser所指出的那样,这实际上是您的代码最初失败的核心原因。所有其他更改都将帮助您避免将来出现其他问题或仅与“代码质量”相关的更改。

那么,这些就是主要的更新。 :) 如果我误解了您想要做的事情或者您有任何问题,请告诉我。

$("document").ready(function() {
 $('#productanddates').on('click', ':button', function () {
  var lastRow = $(this).closest('table').find("tr:last-child");

  var cloned = lastRow.clone();
  cloned.find('input, select').each(function () {
   var id = $(this).attr('id');
   
   var regIdMatch = /^(.+)(\d+)$/; 
   var aIdParts = id.match(regIdMatch);
   var newId = aIdParts[1] + (parseInt(aIdParts[2], 10) + 1);

   $(this).attr('id', newId);
   $(this).attr('name', newId);
  });

  cloned.find("input[type='date']").val('');
  cloned.insertAfter(lastRow);
 });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="blue-bar ta-l">
    <div class="container">
        <h1>Submit Your Insurance Renewal Date(s)</h1>
    </div>
</div>
<div class="grey-bar">
    <div class="container">
        <div class="rounded-box">
            <div>
                <label for="name">Name</label>
                <input type="text" id="name" name="name" autocomplete="off" required />
            </div>
            <div>
                <label for="name">Renewal Dates</label>
            </div>
            <table width="100%" border="0" cellspacing="0" cellpadding="5" id="productanddates" class="border">
                    <tr>
                        <td>
                            <select name="insurance_type1" id="insurance_type1">
                                <option></option>
                                <option>Car</option>
                                <option>Home</option>
                                <option>Van</option>
                                <option>Business</option>
                                <option>GAP</option>
                                <option>Travel</option>
                            </select>
                        </td>
                        <td>
                            <input type="date" name="renewal_date1" id="renewal_date1" />
                        </td>
                        <td>
                            <input type="button" name="button1" id="button1" value="+" />
                        </td>
                    </tr>
            </table>
            <div>
                <label for="telephone_number">Contact Number</label>
                <input type="tel" id="telephone_number" name="telephone_number" pattern="\d{11}" autocomplete="off" required />
            </div>
            <div>
                <label for="email">Email Address</label>
                <input type="email" id="email" name="email" autocomplete="off" required />
            </div>
            <div>
                <input name="submit" type="submit" value="Submit" class="btn">
            </div>
        </div>


现在你要向他收取“一百万美元”的费用,***把小指头放在嘴边***。 - Mouser
LOL,他尽力了……我想帮帮他。 ;) - talemyn
@talemyn,您是我的英雄。我无法感谢您的足够,它完美地运行,并且正是我想要实现的。 - John Woods
@JohnWoods - 太好了...很高兴能帮忙。很高兴它对你有用。 :) - talemyn

0
cloned.insertAfter(thisRow).find('input[type="date"]').val('');

1
欢迎来到Stack Overflow!虽然这段代码可能回答了问题,但提供关于为什么和/或如何回答问题的附加上下文将提高其长期价值。 - NathanOliver

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接