我的视图模型具有以下属性:
public IEnumerable<string> Names { get; set; }
我的视图使用呈现为的简单标记显示该信息:
<div id="names">
<ul>
<li>Name1<img src="/delete.png"/></li>
<li>Name2<img src="/delete.png"/></li>
<li>Name3<img src="/delete.png"/></li>
</ul>
</div>
每个名称上的图像允许您使用一些jQuery删除当前名称
$('#names li img').click(function () {
$(this).closest('li').remove();
});
我希望有一些方法可以将我对jQuery列表的更改反映在我的模型上。这种行为可以通过MVC编辑器模板完成吗?
我知道我可以创建一个带有分隔字符串的隐藏输入并将其解析出来,但我希望我的视图和我的控制器能够轻松处理此列表。
我想如果我在ul元素中添加了一个名字或一个id,那么模型绑定器就能读取li元素并构建一个列表但是没有用。
答案 0 :(得分:6)
尝试使用属性的名称(在您的情况下为“Names”)添加列表项的隐藏输入,并使用方括号中的项目索引。这绝对有效:
<div id="names">
<ul>
<% for (int i = 0; i < Model.Names.Count; i++ ) { string name = Model.Names.ElementAt(i); %>
<li>
<%: Html.Hidden("Names[" + i + "]", name) %><%: name %><img src="/delete.png"/>
</li>
<% } %>
</ul>
</div>
模型绑定器需要某种上下文来决定如何绑定复杂类型。通过提供具有正确名称的隐藏元素,它具有足够的上下文来确定该项属于索引i处的Names属性。如果您不包含索引,则它使用一组有限的项(意味着您无法在列表中添加或删除项,并且调用.Add()
或.Remove()
将抛出异常。)< / p>
虽然我同意jQuery方法可行,但如果页面的其他部分没有使用JSON,那么为什么要使用JSON呢?隐藏元素上的名称完全相同,为其索引提供名称/值对。只有这样,模型绑定器才能为您完成工作(以低于华丽的视图语法的价格)。从好的方面来说,没有必要的javascript来正确绑定这个模型。
如果您使用的是IEnumerable<string>
或ICollection<string>
,则必须像上面的示例一样使用.ElementAt(i)
。如果您使用的是IList<string>
或string[]
,则可以使用索引器。
编辑:解决删除问题
为字符串创建另一个视图模型,因此您在实际视图模型上将拥有IEnumerable<NameViewModel> Names { get; set; }
属性(代替IEnumerable<string>
)。 NameViewModel将如下所示:
public class NameViewModel
{
public string Name { get; set; }
public bool IsDeleted { get; set; }
}
然后,将IsDeleted
的隐藏元素添加到<li>
。请记住,模型绑定器需要适当的上下文名称。将属性添加到索引名称后,隐藏的输入将如下所示:
<%: Html.Hidden("Names[" + i + "].Name", name.Name) %>
<%: Html.Hidden("Names[" + i + "].IsDeleted", name.IsDeleted) %>
在jQuery删除代码中,找到隐藏元素并将值设置为True
,并在列表项上调用.hide()
。当您将表单发布到服务器时,您的操作方法可以找出应该删除的内容,如下所示:
var names = model.Names.Where(name => name.IsDeleted).Select(t => t.Name);
答案 1 :(得分:1)
如果您可以装配jQuery来编译查询字符串,使其对应于IEnumerable<string>
,则可以让Model Binder将查询字符串参数绑定到列表中。
使用jQuery获取每个<li>
并将其附加到查询字符串,如下所示:
?names[0]=val1&names[1]=val2&names[2]=val3 // ...not 100% sure on this...
假设你的行动方法如下:
public ActionResult MyActionMethod(IEnumerable<string> names)
{
// names should correspond to the items you pass in as part of the query string
}
然后,您可以使用操作方法中可用页面上的列表表示。然后,您可以更新模型以对应于该列表。
编辑,但只是为了进一步扩展这一点,假设你想要传递一个YourType列表?
public ActionResult MyActionMethod(IEnumerable<YourType> yourtypes)
{
}
如果您的查询字符串具有每个YourType实例的ID的值,您也可以在查询字符串中包含该值,如下所示
?yourTypeId[0]=1&yourTypeId[1]=2&yourTypeId[2]=3
并且您的Model Binder将使用您传入的ID值创建YourType实例,并将它们添加到列表中。
当然,它与使用jQuery构建查询字符串相比有点不太理想。更理想的方法是将列表序列化为JSON并将JSON对象传递给action方法。