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

MVC技术场景下:HTML表格传控制器及控制器向Razor视图传元素列表

嘿,我来帮你搞定MVC里表格数据和控制器、视图之间的交互问题,结合你给出的HTML片段,咱们分两部分一步步来:

1. 将HTML表格数据传递到MVC控制器

要让表格里的表单数据能被MVC的模型绑定正确识别,核心是遵循索引式命名约定——就像你给出的代码里的TLSPVAssignedAccounts[0].AccountId这种格式。另外,每个行需要一个TLAccountIds.Index的隐藏输入,帮助框架识别列表的索引位置。

第一步:定义对应的模型类

首先创建一个匹配表格数据的模型,用来接收表单提交:

public class TLSPVAssignedAccount
{
    public int AccountId { get; set; }
    public string LOB { get; set; } // 对应你HTML里的"Select LOB"字段
}

第二步:编写表单和控制器接收方法

前端表单(结合你的HTML片段完善)

<form method="post" asp-action="SubmitAccounts">
    <table id="accountTable">
        <thead>
            <tr>
                <th>Select Account</th>
                <th>Select LOB</th>
                <th>Action</th>
            </tr>
        </thead>
        <tbody>
            <!-- 初始行 -->
            <tr>
                <td><input name="TLSPVAssignedAccounts[0].AccountId" value="0" type="text"></td>
                <td><input name="TLSPVAssignedAccounts[0].LOB" type="text" placeholder="Enter LOB"></td>
                <td onclick="RemoveRow(this)">
                    <i class="fa fa-times text-danger"></i>
                </td>
                <td><input name="TLAccountIds.Index" value="0" autocomplete="off" type="hidden"></td>
            </tr>
        </tbody>
    </table>
    <button type="button" onclick="AddNewRow()" class="btn btn-secondary mt-2">Add New Row</button>
    <button type="submit" class="btn btn-primary mt-2 ms-2">Submit</button>
</form>

<script>
    // 移除行的函数
    function RemoveRow(btn) {
        const row = btn.closest('tr');
        row.remove();
        // 删除后更新索引,确保模型绑定正常工作
        updateRowIndices();
    }

    // 动态添加新行的函数
    function AddNewRow() {
        const tableBody = document.querySelector('#accountTable tbody');
        const rowCount = tableBody.children.length;
        const newRow = `
            <tr>
                <td><input name="TLSPVAssignedAccounts[${rowCount}].AccountId" value="0" type="text"></td>
                <td><input name="TLSPVAssignedAccounts[${rowCount}].LOB" type="text" placeholder="Enter LOB"></td>
                <td onclick="RemoveRow(this)">
                    <i class="fa fa-times text-danger"></i>
                </td>
                <td><input name="TLAccountIds.Index" value="${rowCount}" autocomplete="off" type="hidden"></td>
            </tr>
        `;
        tableBody.insertAdjacentHTML('beforeend', newRow);
    }

    // 更新行索引的函数,避免删除后索引断层
    function updateRowIndices() {
        const rows = document.querySelectorAll('#accountTable tbody tr');
        rows.forEach((row, index) => {
            // 更新AccountId输入框的name属性
            const accountInput = row.querySelector('input[name*="AccountId"]');
            accountInput.name = `TLSPVAssignedAccounts[${index}].AccountId`;
            // 更新LOB输入框的name属性
            const lobInput = row.querySelector('input[name*="LOB"]');
            lobInput.name = `TLSPVAssignedAccounts[${index}].LOB`;
            // 更新索引隐藏输入框的值
            const indexInput = row.querySelector('input[name="TLAccountIds.Index"]');
            indexInput.value = index;
        });
    }
</script>

控制器接收方法

在控制器里添加一个HttpPost方法,直接接收List<TLSPVAssignedAccount>类型的参数:

[HttpPost]
public IActionResult SubmitAccounts(List<TLSPVAssignedAccount> TLSPVAssignedAccounts)
{
    // 这里可以处理接收到的数据,比如保存到数据库、验证等
    if (ModelState.IsValid)
    {
        // 业务逻辑处理
        return RedirectToAction("Index");
    }
    // 如果验证失败,返回原视图(如果需要回显数据)
    return View(TLSPVAssignedAccounts);
}
2. 从控制器传递列表到Razor视图并渲染表格

如果需要从控制器把已有的列表数据传递到视图,渲染成可编辑的表格,可以用强类型视图配合Razor循环来实现:

第一步:控制器准备数据

在控制器的HttpGet方法中准备列表数据,传递给视图:

public IActionResult Index()
{
    // 模拟从数据库或其他数据源获取数据
    var assignedAccounts = new List<TLSPVAssignedAccount>
    {
        new TLSPVAssignedAccount { AccountId = 101, LOB = "Retail" },
        new TLSPVAssignedAccount { AccountId = 102, LOB = "Corporate" }
    };
    return View(assignedAccounts);
}

第二步:Razor视图渲染表格

创建强类型视图,模型指定为List<TLSPVAssignedAccount>,用for循环渲染每一行(注意不能用foreach,因为需要索引来生成正确的name属性):

@model List<TLSPVAssignedAccount>

<form method="post" asp-action="SubmitAccounts">
    <table id="accountTable" class="table table-bordered">
        <thead>
            <tr>
                <th>Select Account</th>
                <th>Select LOB</th>
                <th>Action</th>
            </tr>
        </thead>
        <tbody>
            @for (int i = 0; i < Model.Count; i++)
            {
                <tr>
                    <td>
                        <input asp-for="@Model[i].AccountId" class="form-control" />
                        <span asp-validation-for="@Model[i].AccountId" class="text-danger small"></span>
                    </td>
                    <td>
                        <input asp-for="@Model[i].LOB" class="form-control" />
                        <span asp-validation-for="@Model[i].LOB" class="text-danger small"></span>
                    </td>
                    <td onclick="RemoveRow(this)" class="text-center">
                        <i class="fa fa-times text-danger"></i>
                    </td>
                    <td>
                        <input name="TLAccountIds.Index" value="@i" autocomplete="off" type="hidden" />
                    </td>
                </tr>
            }
        </tbody>
    </table>
    <button type="button" onclick="AddNewRow()" class="btn btn-secondary mt-2">Add New Row</button>
    <button type="submit" class="btn btn-primary mt-2 ms-2">Submit Changes</button>
</form>

<!-- 复用之前的JS函数 -->
<script>
    function RemoveRow(btn) {
        const row = btn.closest('tr');
        row.remove();
        updateRowIndices();
    }

    function AddNewRow() {
        const tableBody = document.querySelector('#accountTable tbody');
        const rowCount = tableBody.children.length;
        const newRow = `
            <tr>
                <td><input name="TLSPVAssignedAccounts[${rowCount}].AccountId" value="0" class="form-control" type="text"></td>
                <td><input name="TLSPVAssignedAccounts[${rowCount}].LOB" class="form-control" type="text" placeholder="Enter LOB"></td>
                <td onclick="RemoveRow(this)" class="text-center">
                    <i class="fa fa-times text-danger"></i>
                </td>
                <td><input name="TLAccountIds.Index" value="${rowCount}" autocomplete="off" type="hidden"></td>
            </tr>
        `;
        tableBody.insertAdjacentHTML('beforeend', newRow);
    }

    function updateRowIndices() {
        const rows = document.querySelectorAll('#accountTable tbody tr');
        rows.forEach((row, index) => {
            const accountInput = row.querySelector('input[name*="AccountId"]');
            accountInput.name = `TLSPVAssignedAccounts[${index}].AccountId`;
            
            const lobInput = row.querySelector('input[name*="LOB"]');
            lobInput.name = `TLSPVAssignedAccounts[${index}].LOB`;
            
            const indexInput = row.querySelector('input[name="TLAccountIds.Index"]');
            indexInput.value = index;
        });
    }
</script>

关键注意点

  • 必须用for循环而不是foreach,因为模型绑定需要连续的索引值,foreach无法提供索引。
  • 使用asp-for标签助手可以自动生成符合要求的name属性,还能自动添加验证提示,简化开发。
  • 动态添加/删除行后一定要更新索引,否则提交时模型绑定可能无法正确识别列表数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:43:57