You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET中如何为下拉列表每次调用生成唯一ID

ASP.NET动态添加产品行无法获取数据的解决方案

问题核心原因

  1. 新增行直接复制第一行HTML,所有输入框name仍为Product[0].XXX,ASP.NET模型绑定无法识别为新数组项
  2. changeDropDownValue函数硬编码操作第一行元素,新增行下拉框触发事件时仍修改第一行数据
  3. 所有下拉框ID重复,getElementById仅能获取第一个下拉框

1. 重构AddItem函数,生成合法索引

每次新增行时,以当前表格行数作为新索引,替换复制行内的索引标识,同时给控件设置唯一ID并绑定正确事件:

function AddItem() {
    var table = document.getElementById("product-select");
    var tbody = table.querySelector("tbody");
    var rowCount = tbody.querySelectorAll("tr").length;
    var newIndex = rowCount;

    // 基于第一行生成模板,替换索引和ID
    var templateRow = tbody.querySelector("tr");
    var newRowHtml = templateRow.outerHTML
        .replace(/\[0\]/g, `[${newIndex}]`)
        .replace(/id="productOptions-0"/, `id="productOptions-${newIndex}"`)
        .replace(/onchange="changeDropDownValue(this)"/, `onchange="changeDropDownValue(this)"`);

    var newRow = document.createElement("tr");
    newRow.innerHTML = newRowHtml;
    tbody.appendChild(newRow);
}

function DeleteItem(btn) {
    var row = btn.closest("tr");
    row.remove();
    // 可选:删除后重新排序索引,保证模型绑定兼容性
    reindexRows();
}

// 重新排序行索引辅助函数
function reindexRows() {
    var tbody = document.getElementById("product-select").querySelector("tbody");
    var rows = tbody.querySelectorAll("tr");
    rows.forEach((row, index) => {
        row.querySelectorAll("input, select").forEach(el => {
            if (el.name) el.name = el.name.replace(/\[\d+\]/, `[${index}]`);
            if (el.id.startsWith("productOptions-")) el.id = `productOptions-${index}`;
            if (el.id.startsWith("test-")) el.id = `test-${index}`;
        });
    });
}

2. 修改changeDropDownValue函数,定位当前行

让函数接收当前下拉框元素,通过它定位到所在行,更新对应输入框:

// 把产品数据移到全局,避免重复解析
var Products = @Html.Raw(JsonConvert.SerializeObject(Model.Product));

function changeDropDownValue(selectElement) {
    var selectedProductId = selectElement.value;
    var selectedProduct = Products.find(product => product.ID == selectedProductId);
    if (!selectedProduct) return;

    // 定位当前下拉框所在行
    var row = selectElement.closest("tr");

    // 更新当前行的输入框
    row.querySelector(`input[name*="Description"]`).value = selectedProduct.Description;
    row.querySelector(`input[name*="Quantity"]`).value = selectedProduct.Quantity;
    row.querySelector(`input[name*="UnitPrice"]`).value = selectedProduct.UnitPrice;
    row.querySelector(`input[name*="Discount"]`).value = selectedProduct.Discount;
    row.querySelector(`input[name*="Vat"]`).value = selectedProduct.Vat;
    row.querySelector(`input[name*="NetTotal"]`).value = selectedProduct.NetTotal;
}

3. 调整初始行HTML

修改初始行的下拉框ID和事件绑定,与新增行逻辑统一:

<tr>
    <td>
        <select class="btn btn-success" id="productOptions-0" onchange="changeDropDownValue(this)">
            @foreach (var product in Model.Product)
            {
                <option value="@product.ID">@product.Name</option>
            }
        </select>
    </td>
    <td>
        <input asp-for="Product[0].Description" id="test-0" disabled />
        <span asp-validation-for="Product[0].Description" class="text-danger"></span>
    </td>
    <td>
        <input asp-for="Product[0].Quantity" />
        <span asp-validation-for="Product[0].Quantity" class="text-danger"></span>
    </td>
    <td>
        <input asp-for="Product[0].UnitPrice" disabled />
        <span asp-validation-for="Product[0].UnitPrice" class="text-danger"></span>
    </td>
    <td>
        <input asp-for="Product[0].Discount" />
        <span asp-validation-for="Product[0].Discount" class="text-danger"></span>
    </td>
    <td>
        <input asp-for="Product[0].Vat" disabled />
        <span asp-validation-for="Product[0].Vat" class="text-danger"></span>
    </td>
    <td>
        <input asp-for="Product[0].NetTotal" disabled />
        <span asp-validation-for="Product[0].NetTotal" class="text-danger"></span>
    </td>
</tr>

4. 修正按钮事件绑定

调整按钮的onclick参数,确保删除功能正常:

<button onclick="AddItem()" id="btnadd" type="button" class="btn btn-sm btn-outline-success w-100 visible">Add Product</button>
<button onclick="DeleteItem(this)" id="btnremove" type="button" class="m-2 btn btn-sm btn-danger visible">Delete</button>

关键说明

  • 用行索引作为唯一标识,既符合ASP.NET模型绑定的数组格式要求(Product[N].XXX),又避免了Date.now生成ID无法被模型识别的问题
  • 通过closest("tr")定位当前行,确保每个下拉框仅更新自身所在行的数据
  • 可选的reindexRows函数用于删除行后重新排序索引,保证模型绑定兼容性(ASP.NET支持非连续索引,但连续索引更稳妥)

内容的提问来源于stack exchange,提问作者AFB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 10:50:47