.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
相关产品推荐
相关产品推荐

