如何在无JavaScript的ASP.NET表单中创建含Fruit列表的Basket对象
无JavaScript实现同表单提交Basket与动态数量Fruit的方案
完全不需要前端脚本,靠ASP.NET Core原生模型绑定规则+原生表单提交能力就能实现,核心是通过服务端往返处理新增行的逻辑,所有已填内容不会丢失。
1. 先定义表单专用的视图模型
不要直接用数据库实体类接收表单值,单独建接收提交的模型,增加动作标识字段区分用户是点了「新增水果行」还是「最终提交」:
public class CreateBasketVm { public string Sharp { get; set; } public string Material { get; set; } public List<FruitItem> Fruits { get; set; } = new(); // 标识当前提交的动作类型 public string SubmitAction { get; set; } } public class FruitItem { public string Color { get; set; } public string Taste { get; set; } }
2. 编写后端Action逻辑
两个接口,一个负责初始化表单页,一个负责处理所有表单提交(新增行、最终保存都走这一个Post接口):
// 初始化创建页 [HttpGet] public IActionResult Create() { var vm = new CreateBasketVm { // 默认给1行水果输入位 Fruits = new List<FruitItem> { new() } }; return View(vm); } [HttpPost] public IActionResult Create(CreateBasketVm vm) { // 判断提交动作:如果是点了新增水果 if (vm.SubmitAction == "AddFruit") { // 给水果集合加一个空的新项,返回视图时会自动渲染新的输入行 vm.Fruits.Add(new FruitItem()); // 不要清空ModelState,否则之前用户填的内容会丢失 return View(vm); } // 走到这就是最终提交保存,走正常校验+入库逻辑 if (ModelState.IsValid) { var entity = new Basket { Sharp = vm.Sharp, Material = vm.Material, Fruits = vm.Fruits.Select(f => new Fruit { Color = f.Color, Taste = f.Taste }).ToList() }; // 这里替换成你自己的数据库保存逻辑即可 // _context.Baskets.Add(entity); // await _context.SaveChangesAsync(); return RedirectToAction(nameof(Index)); } // 校验不通过直接返回视图显示错误 return View(vm); }
3. 修改Razor表单代码
核心要遵守ASP.NET Core集合绑定的命名规则:集合输入框的name必须是集合名[索引].属性名的格式,用for循环遍历渲染就能自动生成符合规则的name值,不需要手动写。
<form method="post"> <div style="margin: 8px 0;"> <label>篮子材质:</label> <input asp-for="Material" /> <span asp-validation-for="Material" class="text-danger"></span> </div> <div style="margin: 8px 0;"> <label>篮子形状:</label> <input asp-for="Sharp" /> <span asp-validation-for="Sharp" class="text-danger"></span> </div> <h4>录入水果信息</h4> @for (int i = 0; i < Model.Fruits.Count; i++) { <div style="margin: 10px 0; padding: 10px; border: 1px solid #eee;"> <p>第@(i+1)个水果</p> <div style="margin: 5px 0;"> <label>颜色:</label> <input asp-for="Fruits[i].Color" /> </div> <div style="margin: 5px 0;"> <label>口味:</label> <input asp-for="Fruits[i].Taste" /> </div> </div> } <!-- 新增行按钮:点击后直接提交表单,后端识别动作后加新行返回 --> <button type="submit" name="SubmitAction" value="AddFruit">新增水果行</button> <!-- 最终保存按钮 --> <button type="submit" name="SubmitAction" value="Save" style="margin-left: 20px;">提交保存</button> </form>
实现说明
- 全程没有任何JavaScript代码,所有交互靠原生HTML表单提交能力实现,兼容所有浏览器
- 点击「新增水果行」时,用户之前填的所有篮子信息、已录入的水果信息都会随表单一起提交到后端,后端新增空项后返回视图时,tag helper会自动把之前提交的值回填到输入框,不会出现内容丢失的问题
- 如果需要支持删除行,逻辑完全一致:给每一行加个删除按钮,点击时提交要删除的行索引,后端从Fruits集合里移除对应项再返回视图即可,同样不需要脚本
- 只要严格按照索引格式渲染输入框,ASP.NET Core会自动把提交的多个Fruit值绑定到List集合属性上,不需要额外做参数解析
内容的提问来源于stack exchange,提问作者Yonny
相关产品推荐
相关产品推荐

