将模型发布回包含复杂集合的控制器

时间:2015-10-13 13:31:36

标签: javascript c# json asp.net-mvc

我发布了一个与此类似的问题,但我不相信它明确地说明了我的问题。所以这里有更好的解释!

我正在开发一个C#MVC 5应用程序。我有一个动态列出模型集合属性 A 的页面。此集合中的每个项目都使用一些引导来显示/隐藏它自己的集合属性 B 。所以只是为了澄清:这个模型有一个对象集合,每个对象都有一个与之关联的对象集合。这些对象每个都有一个与它们相关联的复选框,它们也绑定到isChecked布尔值,可用于选择/取消选择项目。选中 A 中的项目框,会自动选中其集合 B 的所有复选框。因此,正如您可能看到的那样,在集合 A 项目上设置复选框的唯一目的是充当其关联集合 B 项目的全部选择。

我正试图在POST时将整个模型传回控制器,然后用它做一些事情,例如抓住所有拥有它们的物品,但遇到了一些问题。

E.g。

@foreach (var category in Model.Categories)
{
  var headerId = category.Name;
  var childCounter = 0;
  @*some divs and headers here*@

  @if (category.Items.Any())
  {
    @*lets give it the ability to check all of its associated items*@
    @Html.CheckBoxFor(d => category.IsChecked, new {id = @headerId, onclick = String.Format("CheckUncheckChildren({0}, {1})", @headerId, category.MenuItems.Count)})
  }
  else
  {
    @Html.CheckBoxFor(d => category.IsChecked)
  }

  @*some other divs and headings*@
  @if (category.MenuItems.Any())
  {
     @foreach (var item in dealItemCategory.MenuItems)
     {
       var childId = childCounter++ + "_" + headerId;
       var serverId = item.Id;

       @*some other divs and headings*@
       @Html.CheckBoxFor(d => item.IsChecked, new {id = @childId})
     }
  }
}

在我的页面上缩小:

  for (var i = 0; i < Model.Categories.Count(); i++)
  {    
    var category = Model.Categories.ElementAt(i);
    var headerId = category.Name;
    @Html.HiddenFor(d => category, new {id = @headerId})

    for (var j = 0; j < Model.Categories.ElementAt(i).Items.Count(); j++)
    {
      var item = Model.Categories.ElementAt(i).Items.ElementAt(j);     
      @Html.HiddenFor(d => item, new {id = j + "_" + @headerId})
    }
  }

在我看来,我在这个复杂的集合的页面上保留了这些属性...(不是我的理解是100%)我已经强制id为这些隐藏的字段,以便它们与id的id相关联复选框。也许不是最好的主意,但这只是我试图让它工作的最后一件事......

现在我有两个选择:

1)相信上述内容,无论何时选中/取消选中复选框,与其关联的集合中的对象都将更改其isChecked布尔值。然后,POST回整个模型,并希望我能够遍历所有检查的项目并做一些很棒的东西。

2)在模型中创建一个字符串属性,以保存此复杂对象集合的JSON表示。当页面处于POSTED状态时,将此JSON字符串更新为复杂集合的状态,该集合有望被更新以检查/取消选中某些项目。然后,POST回整个模型和服务器端我将这个单个对象反序列化为逻辑上等效的复杂集合并从那里开始工作。 即 我的模型更改将添加一个属性:

public string JsonCategories{ get; set; }

然后在视图中我必须发回帖子:

  @Html.HiddenFor(d => d.JsonCategories);

function accept() {
  var categories= @Html.Raw(Json.Encode(Model.Categories));
  var jsonCategories = JSON.stringify(categories);
  var a = $('#JsonCategories').val();
  $('#JsonCategories').val(jsonCategories );
  $("form").submit();
};

尝试解决方案A ,我或者为Categories属性获取null,或者如果我添加@ Html.HiddenFor(d =&gt; d.Categories);我得到一个空对象,数为0。

尝试解决方案B ,我确实为服务器领域的复杂类别获得了一个可爱的JSON表示,但我看到我检查的复选框没有改变isChecked bools让我相信,而JSON对象能够在POST客户端设置为Categories对象,用户完成的所有操作都没有保留,因此最终模型的Categories集合自最初传递给View以来没有改变。 / p>

很抱歉,如果这一切看起来很复杂,那对于像我这样的大三学生来说,我认为我最好问一下,因为我之前从未向控制器发回过清单和内容。

如果有帮助,我很乐意提供更多信息!

最热烈的问候,

1 个答案:

答案 0 :(得分:1)

如果将foreach循环更改为for循环,则可以使用lambda表达式中的循环索引。这应该使引擎输出正确的语法来发布值。例如:

@for (int i = 0; i < Model.Categories.Count(); i++)
{
    ...
    @Html.CheckBoxFor(d => d.Categories[i].IsChecked)
    ...
}

这应该正确地将值绑定到POST请求。生成的html将类似于以下代码段(0表示第一个项目,1表示第二个等):

<input name="Categories[0].IsChecked" ... ></input>

或者,您可以为子集合创建编辑器模板,这将导致您写出此片段以替换当前for循环的位置。

@Html.EditorFor(m => m.Categories)

有关如何执行此操作的详情here

这可以帮助您选择选项1.