可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
The code I am looking to produce is similar to:
<div class="form-group">
<label for="email">Email address</label>
<input type="email" class="form-control" id="email" placeholder="Enter email">
</div>
Using something like this:
@Html.LabelledTextBoxFor(model => model.EmailAddress)
Where the label text get derived from model.EmailAddress
This would be done using Data Annotation e.g.
[Displayname("Email Address]
What is the best way to accomplish this?
Will this affect the auto generated client side JS validation using jquery val?
回答1:
I wrote an extension method, maybe this might help:
public static MvcHtmlString LabelledTextBoxFor<TModel, TResult>(this HtmlHelper<TModel> html, Expression<Func<TModel, TResult>> expression)
{
ExpressionType type = expression.Body.NodeType;
if (type == ExpressionType.MemberAccess)
{
MemberExpression memberExpression = (MemberExpression) expression.Body;
var propName = memberExpression.Member.Name;
var member = memberExpression.Member as PropertyInfo;
var attributes = member.GetCustomAttributes();
StringBuilder sb = new StringBuilder();
foreach (var attribute in attributes)
{
if (attribute is DisplayAttribute)
{
DisplayAttribute d = attribute as DisplayAttribute;
var displayName = d.Name;
sb.Append("<div class=\"form-group\">");
sb.AppendFormat("<label for=\"{0}\">{1}</label>", propName, displayName);
sb.AppendFormat(
"<input type=\"email\" class=\"form-control\" id=\"{0}\" placeholder=\"Enter email\">",
propName);
sb.Append("</div>");
return MvcHtmlString.Create(sb.ToString());
}
}
}
return MvcHtmlString.Create("");
}
You can use default display attribute to specify display name.There is no need for custom attributes.And you can use this extension like this:
@Html.LabelledTextBoxFor(model => model.EmailAddress)
Note: I have tried myself and it is working correctly.
Update: More simple version
public static MvcHtmlString LabelledTextBoxFor2<TModel, TResult>(this HtmlHelper<TModel> html, Expression<Func<TModel, TResult>> expression)
{
ExpressionType type = expression.Body.NodeType;
if (type == ExpressionType.MemberAccess)
{
var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
var displayName = metadata.DisplayName;
var propName = metadata.PropertyName;
StringBuilder sb = new StringBuilder();
sb.Append("<div class=\"form-group\">");
sb.AppendFormat("<label for=\"{0}\">{1}</label>", propName, displayName);
sb.AppendFormat(
"<input type=\"email\" class=\"form-control\" id=\"{0}\" placeholder=\"Enter email\">",
propName);
sb.Append("</div>");
return MvcHtmlString.Create(sb.ToString());
}
return MvcHtmlString.Create("");
}
回答2:
I would use @Html.EditorFor
template. So create EditorTemplates folder in Views/Shared in your MVC project with a name EmailAddress.cshtml - it will display this template for every [DataType(DataType.EmailAddress)]
defined in your model.
So: EmailAddress.cshtml should look sth like this:
<div class="form-group">
<label for="email">@Html.LabelFor(x => x)</label>
@Html.TextBoxFor(x => x, new { @class = "form-control", placeholder = ViewData.ModelMetadata.Watermark })
</div>
Model should look like this:
public class SomeModel {
[DataType(DataType.EmailAddress)]
[Display(Name="Some string for LabelFor", Prompt = "Placeholder in input"]
public string SomeEmail { get; set; }
}
Note here, that I've used Prompt property of Display metadata, which I linked to placeholder via ViewData.ModelMetadata.Watermark
in EmailAddress.cshtml
.
Html.LabelFor
will always take property Name from Display and DataType is needed for linking between EditorTemplates and model property.
And invoke all this "magic" by using
@Html.EditorFor(m=>m.SomeEmail)
on a page, where you use SomeMode
model.
I hope this does make sense.
回答3:
No need to reinvent the wheel. Check out TwitterBootstrapMVC.
The code you'd be writing would look similar to the below:
@Html.Bootstrap().FormGroup().TextBoxFor(model => model.EmailAddress).Placeholder("Enter email")
Disclaimer:
I'm the authot of TwitterBootstrapMVC.
TwitterBootstrapMVC for use on Bootstrap 3 is not free. See details on the website.
回答4:
The Data Annotations go in the viewmodel above the property:
[DisplayName("Email Address")]
public string EmailAddress { get; set; }
Then, in your view, you'd have something like this:
@Html.LabelFor(m => m.EmailAddress)
@Html.TextBoxFor(m => m.EmailAddress, new { @placeholder="Enter email", @class="form-control", @id="email" })