延续上一篇的 ViewModel 结构
现在假设使用者提出要动态 新增/删除 Collection 项目的需求
就可能碰到的问题拆成多个 Case 来看
另外,接下来开始着重於之前强调的 Model Binding,所以文章内就不提 render 後的 html !
这篇先从大家常用的手法来做新增/删除 Collection 项目:
在 js 产生 html 来新增 以及 删除指定的 Html dom !
加入新增
的功能 !
修改 Controller 内的 Action 内容如下:
Get Case01 时,不给定 ViewModel 的预设值
[HttpGet]
public IActionResult Case01()
{
return View();
}
修改 View 内容如下:
加入新增
的功能 !
Table thead 最右边加上一栏,放上新增
按钮
<button type="button" onclick="AddItem(event)">新增</button>
Table tbody 最右边加上一栏
<td></td>
最下面加上 Section Script
@section Scripts {
<script>
window.ItemsCount = @(Model?.Items?.Length ?? 0);
window.ItemHtml = `
<tr>
<td>
<input type="text"
name="Items[i].Name" />
</td>
<td>
<input type="number"
step=1
min=0
name="Items[i].Quantity" />
</td>
<td>
</td>
</tr>
`;
window.AddItem = function () {
const itemHtml = ItemHtml..replaceAll('[i]', `[${ItemsCount}]`);
ItemsCount++;
$('#Items').append(itemHtml);
}
</script>
}
网站执行後,在该页面新增订单项目及输入资料
submit 後,可以看出资料可以如预期的传递 !
接下来,加入删除
的功能 !
从 Case01.cshtml 复制为 Case02.cshtml
修改 Case02.cshtml
把 Table tbody 最後一列改为以下语法
<td>
<button type="button" onclick="DeleteItem(event)">删除</button>
</td>
把 js script 内的 window.ItemHtml 变数中,最後一栏,改为上述的语法
js script 加上以下删除的 function
window.DeleteItem = function (e) {
const btnDom = e.target;
const trDom = $(btnDom).parent().parent();
trDom.remove();
};
重新编译并执行网站,开启刚才新增的页面
送出
按钮在上述第 2 步骤送出前,订单项目当下的 html 会长这样
可以发现
第一个项目是 Items[0]
而
第二个项目是 Items[2]
这个 index 不连续的情况,送到後端後,就会发生 Model Binding
部份失败 !
<tbody id="Items">
<tr>
<td>
<input type="text" name="Items[0].Name" />
</td>
<td>
<input type="number" step="1" min="0" name="Items[0].Quantity" />
</td>
<td>
<button type="button" onclick="DeleteItem(event)">删除</button>
</td>
</tr>
<tr>
<td>
<input type="text" name="Items[2].Name" />
</td>
<td>
<input type="number" step="1" min="0" name="Items[2].Quantity" />
</td>
<td>
<button type="button" onclick="DeleteItem(event)">删除</button>
</td>
</tr>
</tbody>
查看 Log ,会发现找不到 Items[1] 後
Could not bind to model of type 'Project.Models.Day13.OrderItem' as there were no values in the request for any of the properties.
就等於完成该 Property 的 Binding 了 !
Done attempting to bind property
2021-05-25 16:32:49.5225 | 25 | DEBUG | Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexObjectModelBinder | Done attempting to bind model of type 'Project.Models.Day13.OrderItem' using the name 'Items[0]'.
2021-05-25 16:32:49.5225 | 24 | DEBUG | Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexObjectModelBinder | Attempting to bind model of type 'Project.Models.Day13.OrderItem' using the name 'Items[1]' in request data ...
2021-05-25 16:32:49.5387 | 18 | DEBUG | Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ComplexObjectModelBinder | Could not bind to model of type 'Project.Models.Day13.OrderItem' as there were no values in the request for any of the properties.
2021-05-25 16:32:49.5387 | 14 | DEBUG | Microsoft.AspNetCore.Mvc.ModelBinding.Binders.ArrayModelBinder | Done attempting to bind property 'Project.Models.Day13.ViewModel.Items' of type 'Project.Models.Day13.OrderItem[]'.
调整方式,请看 Case03
主要就是参考 Day05.Case03 的格式来调整
在每个 tbody tr 中加上
<input type="hidden" name="Items.index" value="@(i)" />
js script 的 ItemHtml 变数也加上类似上面的语法
<input type="hidden" name="Items.index" value="i" />
js script 的 AddItem 改为以下
window.AddItem = function () {
const itemHtml = ItemHtml.replaceAll('[i]', `[${ItemsCount}]`)
.replaceAll('value="i"', `value="${ItemsCount}"`);
ItemsCount++;
$('#Items').append(itemHtml);
}
让原本的 html 及动态新增的 html 都能加上 name 为 Items.index & value 为指定值 的项目
就可以解决 Case02 因 index 不连续而导致 Model Binding 部份失败 !
以 Case03 的 Code 来说,因为以下二点原因:
接下来,我会改用另一个做法来做 !
这篇先到这里,下一篇来看 动态 新增/删除 Collection 项目 (二)
!
#photos{position:absolute;width:calc(600px*6);z-i...
UninstallView 今天来认识这个不知道是什麽的工具,解除安装概览? UninstallVi...
题号:15 标题:3Sum 难度:Medium Given an integer array num...
前言 一直很想学 JavaScript 但我觉得很难的感觉一直迟迟不敢去碰它,事到如今还是来了,该面...
上一回我们看到,同样的跨年倒数任务,可以用回圈或递回的方式完成。 用回圈通常可以看到某个变数(例如i...