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

.NET MVC动态表单提交问题:实现无跳转单/批量数据提交

问题解决方案

场景说明

你开发的.NET MVC项目已实现动态表单添加功能,目前单个表单提交可成功存入数据库,但会导致页面跳转。需实现无跳转提交单个表单或一键提交所有表单,以下是针对两种场景的调整方案及Action返回值说明。

现有代码

Action代码

public async Task<IActionResult> Create([Bind("TripId,TripDayNumber,TripDate,TimeFrom,TimeTo,ActivitiesId,PkgCityId")] TripDay tripDay)
{
    // save data function to DB
    return View(); // 此处需要修改返回值
}

View页面代码

<div style="border:solid; border-color:black">
    <form asp-action="Create" asp-controller="agentPkGs">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-group">
            <label asp-for="TripDayNumber" class="control-label"></label>
            <input asp-for="TripDayNumber" class="form-control" />
            <span asp-validation-for="TripDayNumber" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label asp-for="PkgCityId" class="control-label"></label>
            <select asp-for="PkgCityId" class="form-control" asp-items="ViewBag.CityID"></select>
        </div>
        <div class="form-group">
            <label asp-for="TripDate" class="control-label"></label>
            <input asp-for="TripDate" class="form-control" />
            <span asp-validation-for="TripDate" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label asp-for="TimeFrom" class="control-label"></label>
            <input asp-for="TimeFrom" class="form-control" />
            <span asp-validation-for="TimeFrom" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label asp-for="TimeTo" class="control-label"></label>
            <input asp-for="TimeTo" class="form-control" />
            <span asp-validation-for="TimeTo" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label asp-for="ActivitiesId" class="control-label"></label>
            <select asp-for="ActivitiesId" class="form-control" asp-items="ViewBag.ActivitiesId"></select>
        </div>
        
        <div class="form-group">
            <input type="submit" value="Create" class="btn btn-primary" />
        </div>
    </form>
</div>

<button onclick="addDiv()">Add Div</button>
<div id="myDiv"></div>

<script>
    function addDiv() {
        var newDiv = $("<div>");
        newDiv.html(`
        <div style="border:solid; border-color:black">
            <form action="/agentPkGs/Create"  method="post">
                <div class="form-group">
                    <label for="PkgCityId">PkgCityId:</label>
                    <select id="PkgCityId" name="PkgCityId" class="form-control">
                        @foreach (var item in ViewBag.CityID)
                        {
                            <option value="@item.Value">@item.Text</option>
                        }
                    </select>
                </div>
                <div class="form-group">
                    <label for="TripDate">TripDate:</label>
                    <input type="text" id="TripDate" name="TripDate" class="form-control" />
                </div>
                <div class="form-group">
                    <label for="TimeFrom">TimeFrom:</label>
                    <input type="text" id="TimeFrom" name="TimeFrom" class="form-control" />
                </div>
                <div class="form-group">
                    <label for="TimeTo">TimeTo:</label>
                    <input type="text" id="TimeTo" name="TimeTo" class="form-control" />
                </div>
                <div class="form-group">
                    <label for="ActivitiesId">ActivitiesId:</label>
                    <select id="PkgCityId" name="PkgCityId" class="form-control">
                        @foreach (var item in ViewBag.ActivitiesId)
                        {
                            <option value="@item.Value">@item.Text</option>
                        }
                    </select>
                </div>
                <div class="form-group">
                    <input type="submit" value="Create" class="btn btn-primary" />
                </div>
            </form>
            <button class='remove-button'>Remove Div</button>
        </div>
        `);
        $("#myDiv").append(newDiv);

        $(document).on("click", ".remove-button", function () {
            $(this).parent().remove();
        });
    }
</script>

注意:动态表单中ActivitiesId对应的select标签,name属性错误写成了PkgCityId,需修正为name="ActivitiesId",否则该字段值无法正确提交到Action。


方案一:无跳转提交单个表单(AJAX方式)

1. 前端修改:拦截表单提交,改用AJAX发送请求

修改所有表单的提交事件,阻止默认跳转行为,通过jQuery AJAX异步提交数据:

// 页面加载完成后绑定事件
$(function() {
    // 绑定所有表单的提交事件
    $("form").on("submit", function(e) {
        e.preventDefault(); // 阻止默认页面跳转
        var form = $(this);
        $.ajax({
            url: form.attr("action"),
            method: form.attr("method") || "POST",
            data: form.serialize(),
            success: function(response) {
                if (response.success) {
                    alert(response.message);
                    // 可选:提交成功后清空当前表单
                    form[0].reset();
                } else {
                    // 显示验证错误
                    var errorMsg = response.errors.join("\n");
                    alert("提交失败:\n" + errorMsg);
                }
            },
            error: function() {
                alert("网络错误,请重试");
            }
        });
    });
});

2. Action修改:返回JsonResult

无需返回View,改为返回JSON格式的响应,告知前端提交结果:

public async Task<IActionResult> Create([Bind("TripId,TripDayNumber,TripDate,TimeFrom,TimeTo,ActivitiesId,PkgCityId")] TripDay tripDay)
{
    if (ModelState.IsValid)
    {
        // 执行保存到数据库的逻辑
        // _context.Add(tripDay);
        // await _context.SaveChangesAsync();
        
        return Json(new { success = true, message = "单个行程日保存成功" });
    }
    // 模型验证失败时返回错误信息
    var errors = ModelState.Values.SelectMany(v => v.Errors.Select(e => e.ErrorMessage));
    return Json(new { success = false, message = "验证失败", errors = errors });
}

方案二:一键提交所有表单(批量保存)

1. 前端结构调整:统一表单容器,字段名改为数组格式

将所有动态添加的表单字段放入同一个<form>中,字段名使用数组命名规则(如TripDays[0].TripDate),确保后端能接收批量数据:

<!-- 修改为单个表单包裹所有内容 -->
<form id="batchForm" asp-action="BatchCreate" asp-controller="agentPkGs" method="post">
    <!-- 初始表单 -->
    <div style="border:solid; border-color:black">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-group">
            <label asp-for="TripDays[0].TripDayNumber" class="control-label"></label>
            <input asp-for="TripDays[0].TripDayNumber" class="form-control" />
            <span asp-validation-for="TripDays[0].TripDayNumber" class="text-danger"></span>
        </div>
        <!-- 其他字段同理,将name改为TripDays[0].XXX -->
        <div class="form-group">
            <label asp-for="TripDays[0].PkgCityId" class="control-label"></label>
            <select asp-for="TripDays[0].PkgCityId" class="form-control" asp-items="ViewBag.CityID"></select>
        </div>
        <!-- 省略其余字段,按数组格式命名 -->
    </div>

    <button onclick="addDiv()">Add Div</button>
    <div id="myDiv"></div>

    <!-- 批量提交按钮 -->
    <div class="form-group mt-3">
        <input type="submit" value="批量保存所有行程" class="btn btn-success" />
    </div>
</form>

<script>
    let formIndex = 1; // 从1开始,初始表单是0
    function addDiv() {
        var newDiv = $("<div>");
        newDiv.html(`
        <div style="border:solid; border-color:black; margin-top:10px">
            <div class="form-group">
                <label for="TripDays_${formIndex}__PkgCityId">PkgCityId:</label>
                <select id="TripDays_${formIndex}__PkgCityId" name="TripDays[${formIndex}].PkgCityId" class="form-control">
                    @foreach (var item in ViewBag.CityID)
                    {
                        <option value="@item.Value">@item.Text</option>
                    }
                </select>
            </div>
            <div class="form-group">
                <label for="TripDays_${formIndex}__TripDate">TripDate:</label>
                <input type="text" id="TripDays_${formIndex}__TripDate" name="TripDays[${formIndex}].TripDate" class="form-control" />
            </div>
            <!-- 其他字段同理,命名为TripDays[${formIndex}].XXX -->
            <div class="form-group">
                <label for="TripDays_${formIndex}__ActivitiesId">ActivitiesId:</label>
                <select id="TripDays_${formIndex}__ActivitiesId" name="TripDays[${formIndex}].ActivitiesId" class="form-control">
                    @foreach (var item in ViewBag.ActivitiesId)
                    {
                        <option value="@item.Value">@item.Text</option>
                    }
                </select>
            </div>
            <button class='remove-button'>Remove Div</button>
        </div>
        `);
        $("#myDiv").append(newDiv);
        formIndex++;

        $(document).on("click", ".remove-button", function () {
            $(this).parent().remove();
        });
    }

    // 拦截批量表单提交,用AJAX实现无跳转
    $(function() {
        $("#batchForm").on("submit", function(e) {
            e.preventDefault();
            var form = $(this);
            $.ajax({
                url: form.attr("action"),
                method: "POST",
                data: form.serialize(),
                success: function(response) {
                    if (response.success) {
                        alert(response.message);
                        form[0].reset();
                        $("#myDiv").empty();
                        formIndex = 1;
                    } else {
                        alert("批量保存失败:\n" + response.message);
                    }
                },
                error: function() {
                    alert("网络错误,请重试");
                }
            });
        });
    });
</script>

2. 新增批量处理Action:接收List<TripDay>参数

// 批量保存的Action
public async Task<IActionResult> BatchCreate(List<TripDay> TripDays)
{
    if (ModelState.IsValid)
    {
        // 批量添加到数据库
        // _context.AddRange(TripDays);
        // await _context.SaveChangesAsync();
        
        return Json(new { success = true, message = $"成功保存{TripDays.Count}条行程日数据" });
    }
    return Json(new { success = false, message = "部分数据验证失败,请检查后重试" });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 17:04:53