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

ASP.NET Core:如何动态添加输入控件并传递数据至控制器

ASP.NET Core 实现动态添加字段并提交嵌套模型数据

1. 控制器实现

创建ServicesController,负责渲染表单页面和接收提交的完整模型数据:

public class ServicesController : Controller
{
    // 渲染创建服务的表单页面
    public IActionResult Create()
    {
        // 初始化空的字段列表,避免视图遍历时报空引用错误
        return View(new Services { ServiceFields = new List<ServiceFields>() });
    }

    // 接收表单提交的数据并处理
    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult Create(Services service)
    {
        if (ModelState.IsValid)
        {
            // 此处添加业务逻辑,比如将数据存入数据库
            // _context.Services.Add(service);
            // _context.SaveChanges();
            return RedirectToAction(nameof(Index));
        }
        // 验证失败时返回原视图,保留用户已输入的内容
        return View(service);
    }
}

2. 前端视图(含动态添加字段逻辑)

在Views/Services/Create.cshtml中编写表单,结合JavaScript实现动态添加ServiceFields输入控件,严格遵循ASP.NET Core模型绑定的命名规则:

@model Services

@{
    ViewData["Title"] = "创建服务";
}

<h1>创建服务</h1>

<form asp-action="Create">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    
    <!-- 服务标题输入框 -->
    <div class="form-group">
        <label asp-for="Title" class="control-label"></label>
        <input asp-for="Title" class="form-control" />
        <span asp-validation-for="Title" class="text-danger"></span>
    </div>
    
    <!-- 服务描述输入框 -->
    <div class="form-group">
        <label asp-for="Description" class="control-label"></label>
        <textarea asp-for="Description" class="form-control"></textarea>
        <span asp-validation-for="Description" class="text-danger"></span>
    </div>
    
    <!-- 动态字段容器 -->
    <div class="form-group">
        <h3>服务字段</h3>
        <div id="serviceFieldsContainer">
            <!-- 遍历已存在的字段(初始化空字段或编辑场景的已有字段) -->
            @for (int i = 0; i < Model.ServiceFields.Count; i++)
            {
                <div class="field-group mb-3">
                    <label asp-for="ServiceFields[i].Title" class="control-label"></label>
                    <input asp-for="ServiceFields[i].Title" class="form-control" />
                    <span asp-validation-for="ServiceFields[i].Title" class="text-danger"></span>
                    <button type="button" class="btn btn-danger mt-1 remove-field">删除</button>
                </div>
            }
        </div>
        <button type="button" id="addFieldBtn" class="btn btn-primary mt-2">添加字段</button>
    </div>
    
    <div class="form-group">
        <input type="submit" value="保存" class="btn btn-success" />
    </div>
</form>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
    
    <script>
        document.addEventListener('DOMContentLoaded', function() {
            const container = document.getElementById('serviceFieldsContainer');
            const addBtn = document.getElementById('addFieldBtn');
            
            // 初始索引值,对应已渲染的字段数量
            let fieldIndex = @Model.ServiceFields.Count;
            
            // 添加字段按钮逻辑
            addBtn.addEventListener('click', function() {
                // 生成符合模型绑定规则的输入框HTML
                const fieldHtml = `
                    <div class="field-group mb-3">
                        <label for="ServiceFields_${fieldIndex}__Title" class="control-label">字段标题</label>
                        <input type="text" class="form-control" id="ServiceFields_${fieldIndex}__Title" name="ServiceFields[${fieldIndex}].Title" />
                        <span class="text-danger field-validation-valid" data-valmsg-for="ServiceFields[${fieldIndex}].Title" data-valmsg-replace="true"></span>
                        <button type="button" class="btn btn-danger mt-1 remove-field">删除</button>
                    </div>
                `;
                container.insertAdjacentHTML('beforeend', fieldHtml);
                
                // 为新添加的删除按钮绑定事件
                bindRemoveEvents();
                fieldIndex++;
            });
            
            // 绑定删除字段的事件
            function bindRemoveEvents() {
                document.querySelectorAll('.remove-field').forEach(btn => {
                    btn.addEventListener('click', function() {
                        this.closest('.field-group').remove();
                    });
                });
            }
            
            // 初始化绑定删除事件
            bindRemoveEvents();
        });
    </script>
}

3. 核心注意事项

  • 模型绑定规则:动态生成的输入框name属性必须遵循ServiceFields[N].Title格式(N为从0开始的连续索引),ASP.NET Core才能自动将数据绑定到List<ServiceFields>集合。
  • 客户端验证:通过引入_ValidationScriptsPartial,动态添加的字段也能触发模型验证逻辑(比如必填项校验)。
  • 空列表初始化:在Get动作中初始化ServiceFields为空列表,避免视图遍历集合时出现空引用异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 11:55:18