Extension to Editor Templates

Topics: ASP.NET MVC
Sep 27, 2014 at 7:41 AM
Edited Sep 27, 2014 at 11:05 AM
I'd like to propose an extension to the Editor template model.

One thing that bugs me about Editor Templates is that they're not entirely self-contained, particularly when redering collections (or IEnumerables that is). And by that, I mean that there may be some setup required to fully render a type, which right now cannot be done with editor templates. You have to write your setup markup around the template (table, table headers, etc.. for instance)

As an example. If I want to render a collection as a table, I need to do this:
<table>
    <tr>
        <th>Header</th>
    </tr>
    @Html.DisplayFor(model => model.collection)
</table>
What I propose is a convention/attribute approach in which you can specify a template header/footer (or pre/post template) to render before and after the collection. There may also be a need for a template separator (since a template can't know when it's the last item in the collection) This could be accplished as such. I don't think we need to go much beyond this, since you can probably achieve any other results using these small subsets (ie item header/footer can probably just be accomplished in the item template, for instance)

EditorTemplates/Type.cshtml
EditorTemplates/Type_Header.cshtml
EditorTemplates/Type_Footer.cshtml
EditorTemplates/Type_Seperator.cshtml

Or, you could put them in a folder per type

EditorTemplates/Type/Item.cshtml
EditorTemplates/Type/Header.cshtml
....

Alternatively, you might create a special @section format or even a new keyword such as @template header {} In which code will be rendered for the header item, this would have the advantage of making the template more self-contained, and create less template file explosions.

In attributes, you could expand the UIHint to include additional information:

[UIHint("MyTemplate", Header="MyTemplate_Header", Footer="MyTemplate_Footer"...]

This would allow, for instance, the rendering of a collection into a table, complete with the outer table declaration, table header, etc...

The goal is to be able to do a single EditorForModel() or DisplayForModel() and be able to get all markup needed for the model rendered. Right now, that's simply not possible, unless you use hacks like creating model properties who's sole purpose is to render pre/post content, and that's just ugly or hand code your pre/post markup in your containing object templates which is less maintainable.

EDIT:

Upon further thought, the whole header/footer mechanism seems antiquated and anachronistic. A better approach might be a (for lack of a better term) "template wrapper" or "template layout". This would probably require a new helper to avoid compatibility issues. Something like this:

EditorTemplates/Type.Layout.cshtml
EditorTemplates/Type.cshtml

Your layout would then have your outer markup, and be rendered with
@Html.EditorLayoutFor(model => model.collection)
and you would use your normal EditorFor within the layout.
<table>
    <tr>
        <th>Header</th>
    </tr>
    @Html.EditorFor(model => model.collection)
</table>
You could then have an extension to the UIHint as such:
[UIHint("MyTemplate", Layout="MyTemplateLayout")]
Or you could follow the Layout paradigm and use @RenderBody and just have a convention where if a .Template.cshtml exists it renders that first, then renders the items in the RenderBody().

Additionally, a Type.ItemSeperator.cshtml would automatically get rendered between items.

It would not make sense to extend the EditorFor method signature to include Layout and Seperator, since for whatever reason the framework has chosen to NOT allow iteration over collections when specifying template explicitly in the EditorFor arguments.

EDIT:

And, it just now occurs to me that (wow, i'm thick), that specifying the template in the arguments is the perfect place to do this sort of template initialization, then use the non-explicit EditorFor template inside. However, I think this is completely unintuitive, and certainly undocumented.

There is still a need for a separator template, which is sorely needed to avoid the "last item" problem. And having an explicit documented layout mechanism to go along with it would make it quite orthogonal.