Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using EditorFor with Twitter Bootstrap to render a form label, input and validation message

I've overridden the default editor template (Object.ascx) to produce form (body) HTML that follows to Twitter Bootstrap's guidelines (http://twitter.github.io/bootstrap/base-css.html#forms) which is executed via Html.EditorForModel().

@if (ViewData.TemplateInfo.TemplateDepth > 1) 
{
    @(Model == null ? ViewData.ModelMetadata.NullDisplayText : ViewData.ModelMetadata.SimpleDisplayText)
} 
else 
{
    foreach (var property in ViewData.ModelMetadata.Properties.Where(m => m.ShowForEdit @*&& m.ModelType != typeof (System.Data.EntityState)*@ && !m.IsComplexType && !ViewData.TemplateInfo.Visited(m))) 
    {
        if (property.HideSurroundingHtml)
        {
            @Html.Editor(property.PropertyName)
        } 
        else 
        {
            <div class="control-group @(!ViewData.ModelState.IsValidField(property.PropertyName) ? "error" : ViewData.ModelState.ContainsKey(property.PropertyName) ? "success" : "" )">
                @if (!string.IsNullOrEmpty(Html.Label(property.PropertyName).ToHtmlString())) 
                {
                    @Html.Label(property.GetDisplayName() + (property.IsRequired ? " *" : ""), new { @class = "control-label" })
                }

                <div class="controls">
                    @Html.Editor(property.PropertyName)
                    @Html.ValidationMessage(property.PropertyName, "*", new { @class = "help-inline" })
                </div>
            </div>
        }
    }
}

This works well unless I want to tweak the form (e.g. change the ordering or add fieldsets). I basically want to separate part of the above code into another editor template, which resulted in Property.ascx. This will render a label, input and validation message for a given property, executed via Html.Editor("{PropertyName"}) or Html.EditorFor(m => m.{PropertyName}).

<div class="control-group @(!ViewData.ModelState.IsValidField(ViewData.ModelMetadata.PropertyName) ? "error" : ViewData.ModelState.ContainsKey(ViewData.ModelMetadata.PropertyName) ? "success" : "" )">
    @if (!string.IsNullOrEmpty(Html.Label(ViewData.ModelMetadata.PropertyName).ToHtmlString())) 
    {
        @Html.Label(ViewData.ModelMetadata.GetDisplayName() + (ViewData.ModelMetadata.IsRequired ? " *" : ""), new { @class = "control-label" })
    }

    <div class="controls">
        @Html.Editor(ViewData.ModelMetadata.PropertyName)
        @Html.ValidationMessage(ViewData.ModelMetadata.PropertyName, "*", new { @class = "help-inline" })
    </div>
</div>

The problem with the above editor template is that it doesn't render the correct input for the given type. So a date/time property will just render a normal text box without the type attribute.

Am I going about this the right way? Should I be using a standard HTML helper or a partial view? If so, how do we handle the generic nature?

like image 445
Andrew Gunn Avatar asked Jun 19 '13 14:06

Andrew Gunn


1 Answers

MVC 5.1 includes a fix for exactly this case, Bootstrap support for editor templates. You can include additional properties for the markup by supplying an anonmyous object as the second parameter to EditorFor

@Html.EditorFor(model => model, new { htmlAttributes = new { @class = "form-control" }, })
like image 191
pnewhook Avatar answered Oct 14 '22 09:10

pnewhook