ASP.Net MVC2自定义模板通过Ajax和模型更新加载

问题描述:

我有一个视图模型与其中的其他对象的集合。ASP.Net MVC2自定义模板通过Ajax和模型更新加载

public ParentViewModel 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public List<ChildViewModel> Child { get; set; } 
} 

public ChildViewModel 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
} 

在我的观点一个我传递一个ParentViewModel作为模型,然后用

<%: Html.EditorFor(x => x) %> 

其中显示的Id和Name属性的表单。

当用户点击一个按钮我打电话通过Ajax动作以在这需要儿童的集合的局部视图加载:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Child>>" %> 
<%: Html.EditorFor(x => x) %> 

然后使用自定义模板儿童以显示形式为每个子传入。

我遇到的问题是Child定制模板创建的表单不使用DefaultModelBinder使用的命名约定。

即字段名(当阿贾克斯加载):代替

[0].FirstName 

Child[0].FirstName 

所以在我的控制器的编辑动作:

[HttpPost] 
public virtual ActionResult Edit(int id, FormCollection formValues) 
{ 
    ParentViewModel parent = new ParentViewModel(); 
    UpdateModel(parent); 

    return View(parent); 
} 

重建来自提交表单的ParentViewModel不起作用。

我想知道什么是通过Ajax完成自定义模板加载然后能够使用UpdateModel的最佳方式。

几件事情的开始是你需要记住默认的ModelBinder是递归的,它会试着弄清楚它需要做什么......所以很聪明。另一件事要记住的是你不需要使用HTML助手,实际的HTML工作正常以及:-)

所以,先用型号,没啥区别在这里..

public class ParentViewModel 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public List<ChildViewModel> Child { get; set; } 
} 

public class ChildViewModel 
{ 
    public int Id { get; set; } 
    public string FirstName { get; set; } 
} 

父局部视图 - 这取ParentViewModel的实例

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ParentViewModel>" %> 

<h2>Parent</h2> 
<%: Html.TextBox("parent.Name", Model.Name) %> 
<%: Html.Hidden("parent.Id", Model.Id) %> 

<% foreach (ChildViewModel childViewModel in Model.Child) 
{ 
    Html.RenderPartial("Child", childViewModel);   
} 
%> 

儿童局部视图 - 这需要的ChildViewModel

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ChildViewModel>" %> 

<h3>Child</h3> 
<%: Html.Hidden("parent.Child.index", Model.Id) %> 
<%: Html.Hidden(string.Format("parent.Child[{0}].Id", Model.Id), Model.Id)%> 
<%: Html.TextBox(string.Format("parent.Child[{0}].FirstName", Model.Id), Model.FirstName) %> 

东西在这一点上要注意的单实例是,指数值是什么用于在列表中的工作出了独特的记录。这不需要是增量值。

那么,你怎么称呼它呢?那么在索引操作中,它将显示需要传入的数据。我已经设置了一些演示数据,并将它在ViewData字典中返回到索引视图。

所以控制器动作......

public ActionResult Index() 
{ 
    ViewData["Message"] = "Welcome to ASP.NET MVC!"; 

    ViewData["Parent"] = GetData(); 

    return View(); 
} 

private ParentViewModel GetData() 
{ 
    var result = new ParentViewModel 
        { 
         Id = 1, 
         Name = "Parent name", 
         Child = new List<ChildViewModel> 
            { 
             new ChildViewModel {Id = 2, FirstName = "first child"}, 
             new ChildViewModel {Id = 3, FirstName = "second child"} 
            } 
        }; 
    return result; 
} 

在现实世界中,你会调用数据服务等

最后索引视图的内容:

<form action="<%: Url.Action("Edit") %>" method="post"> 
    <% if (ViewData["Parent"] != null) { %> 

     <% 
      Html.RenderPartial("Parent", ViewData["Parent"]); %> 

    <% } %> 
    <input type="submit" /> 
</form> 

储蓄

所以现在我们有数据显示我们如何回到行动?那么这是默认模型联编程序将为您在简单的数据类型中为相对复杂的队列所做的事情。所以,你可以设置要发布到作为行动的基本格式:如需要

[HttpPost] 
public ActionResult Edit(ParentViewModel parent) 
{ 

} 

这会给你与原来的ID的更新的详细信息(从隐藏字段),因此您可以更新/编辑。

通过Ajax

你在你的问题中加载自定义模板通过AJAX提到

新的孩子,你的意思是如何给用户增加的另一个孩子没有回发的选项?

如果是这样,你做这样的事情......

添加操作 - 需要一个行动,这将返回一个新ChildViewModel

[HttpPost] 
public ActionResult Add() 
    { 
     var result = new ChildViewModel(); 
     result.Id = 4; 
     result.FirstName = "** to update **"; 
     return View("Child", result); 
    } 

我已经给它一个id,方便的演示目的。

然后您需要一种调用代码的方式,因此您需要更新的唯一视图是主索引视图。这将包括获取操作结果的JavaScript,调用代码的链接以及要附加到HTML的目标HTML标记。另外不要忘记在master页面或视图的顶部添加对jQuery的引用。

索引视图 - 已更新!

<script type="text/javascript"> 

    function add() { 

     $.ajax(
      { 
       type: "POST", 
       url: "<%: Url.Action("Add", "Home") %>", 
       success: function(result) { 
        $('#newchild').after(result); 
       }, 
       error: function(req, status, error) { 

       } 
     }); 
    } 

</script> 

<form action="<%: Url.Action("Edit") %>" method="post"> 
    <% if (ViewData["Parent"] != null) { %> 

     <% 
      Html.RenderPartial("Parent", ViewData["Parent"]); %> 

    <% } %> 
    <div id="newchild"></div> 

    <br /><br /> 
    <input type="submit" /> <a href="#" onclick="JavaScript:return add();">add child</a> 
</form> 

这将调用添加动作,并追加回应时,它返回到newChild对象DIV提交按钮的上方。

我希望长篇文章很有用。

Enjoy :-)

+0

你的长文章非常有用,非常感谢。看起来这正是我所需要的。 – Chris 2010-07-25 09:17:05

+0

@Chris - 真棒,很高兴它的有用:-) – WestDiscGolf 2010-07-25 20:10:21

嗯...我个人推荐使用的,而不是一个HTML结果的JSON结果,你在页面拨弄......

使系统更清洁。和你的回发工作;-)

+0

我不确定JSON结果如何帮助?我需要加载到页面的响应不仅仅是数据。并且表单需要具有正确的命名约定,以便在回发到服务器时模型绑定起作用。 – Chris 2010-07-23 11:47:50

+0

你可以得到每个AJAX的结果,并用结果替换表单中的数据... – cRichter 2010-07-23 11:59:07

我发现了另一种方法来完成这个工作在我的特殊情况。

在部分

,而不是加载的通过通过Ajax是强类型的子集,如:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Child>>" %> 

我创建了一个强类型的视图到父类型,然后叫列表,像这样的EditorFor:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Parent>" %> 
<%: Html.EditorFor(x => x.ChildList) %> 

这然后调用自定义显示模板,其结果是,所有的HTML元素得到正确命名和默认模式粘结剂可以把一切重新走到一起。