Nested edit templates in mvc razor
I have seen many versions of this question but the answers always turn into "you don't need to do that" and never an answer.
I have a list of attributes about a product that I want to show in an unordered list with checkboxes to select particular attributes.
In My Model:
public List<ProductAttribute> ProductAttributes {get;set;}
in my Create.cshtml:
<div Class="ProductAttributes">
@Html.EditorFor(m => m.ProductAttributes, "ProductAttributeSelectorList")
</div>
In my ProductAttributeSelectorList.cshtml:
@model List<Models.DisplayLocationAttribute>
<div class="AttributeSelector">
<ul>
@foreach (var item in Model)
{
<li>
@Html.Ed开发者_开发技巧itorFor(_ => item, "EditLocationAttributeList")
</li>
}
</ul>
</div>
And finally, in my EditLocationAttributeList.cshtml
@model Models.DisplayLocationAttribute
@Html.HiddenFor(m => m.Id)
@Html.CheckBoxFor(m => m.IsSelected)
<a href="#" alt="@Model.Description" >@Model.Name</a>
This all displays on the page perfectly I can style it like I want with CSS, but when the submit returns, my model.ProductAttributes collection is null.
I know I can bind directly to the EditLocationAttributeList and it will display and return a populated model.ProductAttributes if I use this:
@Html.EditorFor(m => m.ProductAttributes, "EditLocationAttributeList")
but now I do not have the unordered list that I would like to have. I could treat the template like an Item Template and have the line item tags embeded in that template but that seems smelly to have a template that is tightly coupled to another template.
Any Ideas?
Thanks in advance,
Tal
model.ProductAttributes
is null, because the DefaultModelBinder is not able to reference each DisplayLocationAttribute back to the ProductAttribute property of your model. The simplest solution is to name your list elements as an array, so that for example each IsSelected element is named in the style ProductAttributes[n].IsSelected
.
Add the following to ProductAttributeSelectorList.cshtml
:
@model List<Models.DisplayLocationAttribute>
@{
var i = 0;
}
<div class="AttributeSelector">
<ul>
@foreach (var item in Model)
{
this.ViewData.TemplateInfo.HtmlFieldPrefix = "ProductAttributes[" +
i.ToString() + "]";
i++;
<li>
@Html.EditorFor(_ => item, "EditLocationAttributeList")
</li>
}
</ul>
</div>
@{
this.ViewData.TemplateInfo.HtmlFieldPrefix = "";
}
This will give you an indexed array, which the DefaultModelBinder will be able to associate to ProductAttributes. However, it builds a hard dependency to the name ProductAttributes
. You can get around the hard dependency by several methods, such as passing the property name in the ViewBag.
精彩评论