David V. Corbin
David V. Corbin

Reputation: 397

ASP.NET MVC - Compound Model

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.

Upvotes: 0

Views: 178

Answers (1)

Monah
Monah

Reputation: 6784

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

Upvotes: 1

Related Questions