MVC4 binds model to ICollection or List in partial
Given the model
public class Task
{
public int TaskId { get; set; }
public string Title { get; set; }
public ICollection<SomeData> Information { get; set; }
}
Where
public class SomeData
{
public int SomeDataId { get; set; }
public string Description { get; set; }
}
I have an idea
@model myProject.Models.Task
<div>
@Html.LabelFor(model => model.Title)
</div>
<table>
@Html.Partial("_InformationEdit", Model.Information.ToList(), new ViewDataDictionary(Html.ViewDataContainer.ViewData) {
TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "Information" }})
</table>
and my partial
@model IList<myProject.Models.SomeData>
@for (int i = 0; i < Model.Count(); i++)
{
<tr>
<td>
@Html.EditorFor(modelItem => Model[i].Description)
</td>
</tr>
}
However
My Html fields are rendered like
<input class="text-box single-line" id="Information__0__Description" name="Information.[0].Description" type="text">
If names should be Information[0].Description
. It got an extra point there, so it won't revert to the model correctly when posted. How can I fix this?
According to model binding to list I can see what my ID should be, but I just can't figure out the correct syntax.
Also, is there a more elegant way to achieve this IEnumerable
with using @foreach
?
Connected:
ASP.Net MVC4 binds "create view" to the model containing the list
ASP.NET MVC Model Binding IList <gt; Parameter
Changing my partial to
@model IList<myProject.Models.SomeData>
@{
var Information = Model;
}
@for (int i = 0; i < Information.Count(); i++)
{
<tr>
<td>
@Html.EditorFor(modelItem => Information[i].Description)
</td>
</tr>
}
Works, but it seems a little odd!
I am assuming the bound object has the same name as the property to which it should be bound with some magic ... Other suggestions or explanations are appreciated!
You can use <input...
like this:
Page:
<table>
@Html.Partial("_InformationEdit", Model.Information)
</table>
Partial page:
@for (int i = 0; i < Model.Count(); i++)
{
<tr>
<td>
<input class="text-box single-line" id="Information[@i]Description" name="Information[@i].Description" type="text" value="@Model[i].Description" />
</td>
</tr>
}
Or, to be able to pass the prefix, as in your example, you can keep the page code the same and change your partial, for example:
Page:
<table>
@Html.Partial("_InformationEdit", Model.Information,
new ViewDataDictionary(Html.ViewDataContainer.ViewData)
{
TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = "Information" }
})
</table>
Partial page:
@for (int i = 0; i < Model.Count(); i++)
{
<tr>
<td>
@{
string fieldName = string.Format("{0}[{1}].Description", ViewData.TemplateInfo.HtmlFieldPrefix, i);
<input class="text-box single-line" id="@fieldName" name="@fieldName" type="text" value="@Model[i].Description" />
}
</td>
</tr>
}
your partial should be:
@model IList<myProject.Models.SomeData>
@for (int i = 0; i < Model.Count(); i++)
{
<tr>
<td>
@Html.EditorFor(model => model[i].Description)
</td>
</tr>
}
also easier to read if you replace i with the element name