0

I have a trivial web app with the following model:

public class SillyModel
{
    public SillyModel()
    { Id = Guid.NewGuid();  Children = new List<SillyModel>(); }
    [Key]
    public virtual Guid Id { get; set; }
    public virtual string Value { get; set; }
    public virtual List<SillyModel> Children { get; set; }
}

}

I have an Edit View of:

@model WebApplication1.Models.SillyModel
@{
    ViewBag.Title = "Edit";
}
<h2>Edit</h2>
@using (Html.BeginForm())
{

@Html.AntiForgeryToken()

@Html.Partial("EditPartial", Model)

<div class="form-horizontal">
    <h4>SillyModel</h4>
    <hr />
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Save" class="btn btn-default" />
        </div>
    </div>
</div>
}

With the Partial:

@model WebApplication1.Models.SillyModel

@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.Id)

<div class="form-group">
    @Html.LabelFor(model => model.Value, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.Value, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Value, "", new { @class = "text-danger" })
    </div>
    @foreach (var item in Model.Children)
    {
        @Html.Partial("EditPartial", item)
    }
</div>

The rendering is Fine! But for the life of me (well at least 3 days of struggle) I can not get it so that the returned model is properly bound! [No children are returned]

I am at my wits end.

David V. Corbin
  • 344
  • 1
  • 10
  • What do you mean *so returned model is properly bound*? Where is your controller code? – CodingYoshi Dec 04 '17 at 21:36
  • You cannot use `@Html.Partial("EditPartial", item)` to generate form controls for a collection unless your pass the `HtmlFieldPrefix` to the partial (refer [this answer](https://stackoverflow.com/questions/29808573/getting-the-values-from-a-nested-complex-object-that-is-passed-to-a-partial-view/29809907#29809907)). However the correct approach is to use an `EditorTemplate` or a `for` loop - refer [this example](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable/30094943#30094943) –  Dec 04 '17 at 22:44

1 Answers1

1

You have to re-structure the way you are coding a little

  1. In the Views/YourController, add a folder called EditorTemplates if not yet exists and add a view named SillyModel and copy the code from EditPartial to this new view
  2. You change the foreach to for loop to decorate the controls with index

The code

~/Views/YourController/EditorTemplates/SillyModel.cshtml

@model WebApplication1.Models.SillyModel

@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.Id)

<div class="form-group">
    @Html.LabelFor(model => model.Value, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.Value, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Value, "", new { @class = "text-danger" })
    </div>
    @for (var index=0; index<Model.Children.Count;index++)
    {
        @Html.EditorFor(model=>Model.Children[index])
    }
</div>

~/Views/YourController/Edit

instead of @Html.Partial("EditPartial", Model), use @Html.EditorFor(m=>m)

Explanation

  1. By adding the EditorTemplates/SillyModel , now you can call @Html.EditorFor(model=>Model.Children[index]) and your custom editor will be rendered
  2. You need to use indexed controls in order Binding to the Model succeeded

Hope this will help you

Monah
  • 6,714
  • 6
  • 22
  • 52
  • You do not need the `@for (var index=0; index m.Children)` - the `EditorFor()` method accepts `IEnumerable` and generates the correct html for each item in the collection –  Dec 04 '17 at 22:46
  • I can confirm that this works.... Now if I can just get EF to persist (but that will be a different question). – David V. Corbin Dec 05 '17 at 00:49
  • @DavidV.Corbin If my answer helped you, kindly vote up and mark it as answer – Monah Dec 05 '17 at 06:06