2010-07-23 30 views
2

我有一個視圖模型與其中的其他對象的集合。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的最佳方式。

回答

9

幾件事情的開始是你需要記住默認的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

2

嗯...我個人推薦使用的,而不是一個HTML結果的JSON結果,你在頁面撥弄......

使系統更清潔。和你的回發工作;-)

+0

我不確定JSON結果如何幫助?我需要加載到頁面的響應不僅僅是數據。並且表單需要具有正確的命名約定,以便在回發到服務器時模型綁定起作用。 – Chris 2010-07-23 11:47:50

+0

你可以得到每個AJAX的結果,並用結果替換表單中的數據... – cRichter 2010-07-23 11:59:07

1

我發現了另一種方法來完成這個工作在我的特殊情況。

在部分

,而不是加載的通過通過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元素得到正確命名和默認模式粘結劑可以把一切重新走到一起。