Reputation: 11673
I find myself writing this a whole lot in my views:
<div class="form-group">
@Html.LabelFor(x => x.City)
@Html.EditorFor(x => x.City)
@Html.ValidationMessageFor(x => x.City)
</div>
I'd really like to put this in a Partial _Field.cshtml
, something like this:
@model //what model type???
<div class="form-group">
@Html.LabelFor(Model)
@Html.EditorFor(Model)
@Html.ValidationMessageFor(Model)
</div>
That could then be called by:
@Html.Partial("_Field", x => x.City)
What would the @model
type in my partial be if I wanted to accomplish something like this?
UPDATE This works, but I'd rather use a partial for ease of changing the template:
public static MvcHtmlString Field<TModel, TItem>(this HtmlHelper<TModel> html, Expression<Func<TModel, TItem>> expr)
{
var h = "<div class='form-group'>";
h += $"{html.LabelFor(expr)}{html.EditorFor(expr)}{html.ValidationMessageFor(expr)}";
h += "</div>";
return MvcHtmlString.Create(h);
}
Upvotes: 3
Views: 332
Reputation: 239290
That's not possible. However, what you want is very similar to editor templates. Essentially, you just create a view in Views/Shared/EditorTemplates
named after one of the following conventions:
One of the members of the DataType
enum (EmailAddress.cshtml, Html.cshtml, PhoneNumber.cshtml, etc.). You would then apply the appropriate DataType
attributes to your properties:
[DataType(DataType.EmailAdress)]
public string Email { get; set; }
Any thing you want, in conjunction with the UIHint
attribute:
[UIHint("Foo")]
public string Foo { get; set; }
Which would then correspond to a Foo.cshtml editor template
In your views, then, you simply use Html.EditorFor
:
@Html.EditorFor(x => x.City)
Then, for example, you could have Views/Shared/EditorTemplates/String.cshtml
as:
<div class="form-group">
@Html.Label("", new { @class = "control-label" })
@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = "form-control" })
@Html.ValidationMessage("")
</div>
(The empty quotes are placeholders. Razor will automatically fill in the appropriate property name, thankfully.)
Calling EditorFor
, then, will print all of this, rather than just the default text input. You can take this much further, as well. I have some articles on my blog that goes into greater detail, if you're interested.
UPDATE
It's worth mentioning a few features of EditorFor
:
You can pass a template directly to the call, meaning you can customize what template is used on the fly and per instance:
@Html.EditorFor(x => x.City, "MyCustomEditorTemplate")
You can pass additionalViewData
. The members of this anonymous object are added to the ViewData
dynamic dictionary. Potentially, you could use this to branch within your editor template to cover additional scenarios. For example:
@Html.EditorFor(x => x.City, new { formGroup = false })
Then in your editor template:
@{ var formGroup = ViewData["formGroup"] as bool? ?? true; }
@if (formGroup)
{
<!-- Bootstrap form group -->
}
else
{
<!-- Just the input -->
}
Upvotes: 3