用于IEnumerable <string>的ASP.NET MVC模型绑定可以改变模型吗?</string>

时间:2010-08-24 20:28:45

标签: jquery asp.net-mvc

我的视图模型具有以下属性:

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元素并构建一个列表但是没有用。

2 个答案:

答案 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方法。