2013-07-01 37 views
0

我已經把我的頭髮撕掉了,所以我正在尋求幫助。我已經構建了一個簡短的遞歸HTML助手來顯示列表的列表。我想將任何編輯返回給控制器。一個孩子的孩子不斷回來。當我刪除遞歸,並強制通過「for循環」的第二層時,它似乎工作。任何線索?我即將在RAZOR上撒毛巾,並學習如何在Jquery中完成所有這些...MVC4不會發布帶有嵌套遞歸列表的對象

根據我的代碼,問題出現在這裏,當模型發佈回來時(您會在在後的ActionResult方法註釋):

Node.Name是確定

Node.Children [0]請將.Name是確定

Node.Children [1]請將.Name是確定

節點。兒童[1]。兒童= null(這裏說謊的問題!)

控制器代碼

 public ActionResult Y() 
    { 
     Node driverTree = new Node() { Name="Level1", Children = new List<Node>() }; 
     driverTree.Children.Add(new Node() { Children = null, Name = "Level2A" }); 
     driverTree.Children.Add(new Node() {Name ="Level2B", Children = new List<Node> {new Node{Name="Level3A", Children=null}, 
                       new Node{Name="Level3B", Children=null}} 
     }); 
     return View(driverTree); 
    } 
    [HttpPost] 
    public ActionResult Y(Node Node) 
    { 
     //Keeps returning: 
      // Node.Name is ok 
      // Node.Children[0].Name is ok 
      // Node.Children[1].Name is ok 
      // Node.Children[1].Children = null (HERE LIES THE PROBLEM!) 
     int x = 5; // 
     return View(); 
    } 
} 

public class Node 
{ 
    public string Name { get; set; } 
    public List<Node> Children { get; set; } 
    public bool IsChecked { get; set; } 
} 

查看代碼

@model JqueryUITests.Controllers.Node 
@section Scripts { 
@Scripts.Render("~/bundles/jqueryval") 
<script src="../../Scripts/jquery-ui-1.10.3.min.js" type="text/javascript"></script> 
<script src="../../Scripts/jquery-ui.unobtrusive-2.1.0.min.js" type="text/javascript"></script> 
} 

@helper ShowTree(List<JqueryUITests.Controllers.Node> children) 
{ 
<ul> 
    @for (int i = 0; i < children.Count;i++) 
    { 
     <li> 
      @Html.EditorFor(x => children[i].Name) 
      @if (children[i].Children != null) 
      { 
       @ShowTree(children[i].Children) 
      } 
     </li> 
    } 
</ul> 
} 
@using (Html.BeginForm()) 
{ 
<ul id="tree"> 
    <li> 
     @Html.EditorFor(x=>Model.Name) 
     @ShowTree(Model.Children) 
    </li> 
</ul> 
<p> 
    <input type="submit" value="Create" /> 
</p> 

}

HTML代碼

<form action="/X/Y" method="post"> <ul id="tree"> 
    <li> 
     <input class="text-box single-line" id="Name" name="Name" type="text" value="Level1" /> 
      <ul> 
     <li> 
      <input class="text-box single-line" id="children_0__Name" name="children[0].Name" type="text" value="Level2A" /> 
     </li> 
     <li> 
      <input class="text-box single-line" id="children_1__Name" name="children[1].Name" type="text" value="Level2B" /> 
<ul> 
     <li> 
      <input class="text-box single-line" id="children_0__Name" name="children[0].Name" type="text" value="Level3A" /> 
     </li> 
     <li> 
      <input class="text-box single-line" id="children_1__Name" name="children[1].Name" type="text" value="Level3B" /> 
     </li> 
</ul> 
     </li> 
</ul> 

    </li> 
</ul> 
<p> 
    <input type="submit" value="Create" /> 
</p> 

+0

你可以發佈呈現的HTML標記嗎? – Nenad

+0

你的:@ShowTree(children [i] .Children)永遠不會呈現。你確定它在視圖渲染過程中不是空的嗎? – Nenad

+0

我在屏幕上看到它,所以它正在渲染。在我粘貼的html標記的底部,有一堆「li」和「ul」(對此很抱歉)。但是,從視覺上看,這一切都是按順序排列的 – user2014503

回答

2

列表正在爲每個節點呈現項目,但它沒有正確地爲每個節點呈現名稱屬性。

Razor通過使用name屬性來處理列表,以便在輸入被回發並重新創建模型時創建數組。例如

List<Foo> AllMyFoos { new Foo { Id = 1 }, new Foo { Id = 2 }, new Foo { Id = 3 }} 

將呈現(按照上面的實施例)這樣的:

<input type="text" name="AllMyFoos[0].Id" /> 
<input type="text" name="AllMyFoos[1].Id" /> 
<input type="text" name="AllMyFoos[2].Id" /> 

引擎蓋下的模型在剃刀和MVC結合然後重新創建的Foo對象的列表,並將其傳遞到您的控制器方法。

您的遞歸方法的問題是,當您使用子節點列表調用它時,每個子節點的索引正在呈現,並且您正在丟失將其定義爲另一個節點的子節點的信息。

這有道理嗎?

看看這個SO問題,並閱讀關於顯示模板集合類型的答案 - 這是實現您的目標的更好方法。

SO Display Templates Answer

+0

謝謝。我認爲它必須是一些Razor的東西,因爲當我用2nd for循環替換遞歸時,它看起來都是按順序排列的。你會建議在jQuery中試試這個標記是否是一個更好的路徑?非常感謝。 – user2014503

+0

如果你更樂意使用jQuery,那就去做吧。你需要能夠保持它(大概),所以無論你更舒適。我總是會學習新東西,特別是在像MVC這樣的大型框架中。在你的立場中,我會問自己的問題是:'我如何在jQuery中做到這一點?'然後'爲什麼我不能在剃刀中這樣做?'。 – dav83

+1

@ dav83 - 這不是「一些剃鬚刀的東西」,它是一個HTTP事物。您正在發送重複的命名對象。它確實與剃刀無關,這是因爲你沒有正確使用Html Helpers(它是MVC的一部分,而不是Razor)。 –

1

問題是清楚的:

@Html.EditorFor(x => children[i].Name) 

通常x表示模型,然後性質格式x.children[i].Name的。下一級將是x.children [i] .children [j] .Name。 EditorFor從該表達式導出id和名稱<input />字段。在你的情況下,表達式總是children[i].Name,所以它打破了id/name相對於你的根Model的映射。

我不確定是否有一種好方法可以像您想要的那樣進行遞歸渲染。也許使用非lambda版本Html.Editor(string expression),您可以在其中構建表達式作爲字符串,在代碼中考慮嵌套級別(例如:@Html.Editor("Children[1].Children[2].Name"))。

您將負責生成適當的值"Children[1].Children[2].Name"

+0

因爲我已經用MVC3實現了編輯器,所以不僅可以處理複雜的模型,而且可以在複雜模型中添加/刪除任何模型,並且無需加載編輯器儘管如此,它確實需要一些折騰。 – JayC

+0

這是味道的部分問題。一次性編輯(並回傳)完整的遞歸模型,就像這個問題一樣,對我來說似乎不太方便用戶。它甚至不包括添加/刪除子節點。 – Nenad

0

在dav83關於顯示模板的評論中進行了擴展。它應該看起來像這樣。

文件

查看\ DisplayTemplates \ Node.cshtml

@model JqueryUITests.Controllers.Node 

<li> 
    @Html.EditorFor(x => x.Name) 
    @if (Model.Children != null) 
    { 
     <ul> 
      @Html.Editor(x => x.Children) 
     </ul> 
    } 
</li> 

現在您的角度提出。

@model JqueryUITests.Controllers.Node 
@section Scripts 
{ 
    @Scripts.Render("~/bundles/jqueryval") 
    <script src="../../Scripts/jquery-ui-1.10.3.min.js" type="text/javascript"></script> 
    <script src="../../Scripts/jquery-ui.unobtrusive-2.1.0.min.js" type="text/javascript"></script> 
} 

@using (Html.BeginForm()) 
{ 
    <ul id="tree"> 
     @Html.EditorForModel() 
    </ul> 
    <p> 
     <input type="submit" value="Create" /> 
    </p> 
} 

MVC將使用您的模型的Node DisplayTemplate呈現HTML。此外,當您撥打@Html.EditorFor(x => x.Children)時,它將使用顯示模板呈現集合中的每個項目。這是您獲得遞歸構建整個樹的地方。

此外,它還會跟蹤它在樹中的位置並正確命名HTML元素,允許您的樹像預期的那樣發佈。