2013-07-01 42 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元素,允许您的树像预期的那样发布。