C# 渲染的局部视图与模型不匹配
因此,我编写了一些代码,允许在ASP.NET MVC中使用AJAX动态添加和删除集合中的元素。向集合中添加新项的工作方式与预期相同,但删除项的工作方式与预期不同。模型集合按预期更新(相应的项按索引删除),但呈现的HTML始终显示最后一个项已删除(而不是指定索引处的项) 例如,假设我有以下项目:C# 渲染的局部视图与模型不匹配,c#,asp.net-mvc,asp.net-mvc-5,C#,Asp.net Mvc,Asp.net Mvc 5,因此,我编写了一些代码,允许在ASP.NET MVC中使用AJAX动态添加和删除集合中的元素。向集合中添加新项的工作方式与预期相同,但删除项的工作方式与预期不同。模型集合按预期更新(相应的项按索引删除),但呈现的HTML始终显示最后一个项已删除(而不是指定索引处的项) 例如,假设我有以下项目: 福 酒吧 巴兹 当我单击名为“Foo”的项旁边的“remove”时,我希望得到的呈现HTML如下所示: 酒吧 巴兹 当我通过控制器操作进行调试时,情况似乎就是这样,因为模型上的Names集合只包含
- 福
- 酒吧
- 巴兹
- 酒吧
- 巴兹
- 福
- 酒吧
@model List<string>
@for (int i = 0; i < Model.Count; i++)
{
<p>
@Html.EditorFor(m => m[i]) @Html.ActionLink("remove", "RemoveName", null, new { data_target = "names", data_index = i, @class = "link link-item-remove" })
</p>
}
这是因为您回发了模型,并且模型的值由
DefaultModeBinder
添加到ModelState
。生成表单控件的HtmlHelper
方法(在您的例子中是@Html.EditorFor(m=>m.Names,“Names”)
)使用ModelState
中存在的值(而不是实际的属性值)。此行为的原因将在本手册的第二部分中解释
在您的情况下,ModelState
值为
Name[0]: Foo
Name[1]: Bar
Name[2]: Baz
因此,即使您返回的更新模型只包含Name[0]:Bar
和Name[1]:Baz
,但是EditorFor()
方法在第一次迭代中将检查ModelState
值Name[0]
,发现它存在并输出Foo
您可以通过在返回视图之前使用ModelState.Clear()
来解决这个问题(尽管正确的方法是使用PRG模式),但在您的情况下,这一切似乎都不是必需的,尤其是必须回发整个模型。您可以简单地回发项目的索引或名称
值(或者如果它是一个复杂对象,则是一个ID值),删除该项目并返回一个JsonResult
,指示是否成功。然后在ajaxsuccess
回调中,从DOM中删除该项
@model List<string>
@for (int i = 0; i < Model.Count; i++)
{
<p>
@Html.EditorFor(m => m[i]) @Html.ActionLink("remove", "RemoveName", null, new { data_target = "names", data_index = i, @class = "link link-item-remove" })
</p>
}
@model MvcPlayground.Models.DemoViewModel
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Demo</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="container-collection" id="names">
@Html.EditorFor(m => m.Names, "Names")
</div>
@Html.ActionLink("Add New", "AddName", "Demo", null, new { data_target = "names", @class = "btn btn-addnew" })
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
$('form').on('click', '.btn-addnew', function (e) {
e.preventDefault();
var form = $(this).closest('form');
var targetId = $(this).data('target');
var target = form.find('#' + targetId);
var href = $(this).attr('href');
$.ajax({
url: href,
cache: false,
type: 'POST',
data: form.serialize()
}).done(function (html) {
target.html(html);
});
});
$('form').on('click', '.link-item-remove', function (e) {
e.preventDefault();
var form = $(this).closest('form');
var targetId = $(this).data('target');
var target = form.find('#' + targetId);
var href = $(this).attr('href');
var formData = form.serialize() + '&index=' + $(this).data('index');
$.ajax({
url: href,
cache: false,
type: 'POST',
data: formData
}).done(function (html) {
target.html(html);
});
});
Name[0]: Foo
Name[1]: Bar
Name[2]: Baz