We have a model with properties decorated with [Required] which works great for validation. However, what we'd like to do is mark those required fields in the view with an asterisk (or some other style) to denote they are required before the user enters any data for validation.
I don't seem to be able to find anything built into the MVC framework to allow me to do this and theref开发者_运维问答ore wondered if anyone else had already solved this and how?
Ultimately what we're trying to prevent is the need to change code in two places if we subsequently remove a [Required] from a model property.
Many Thanks
You can build your own HtmlHelper extension for this:
public static string RequiredMarkFor<TModel, TValue>(this HtmlHelper html, Expression<Func<TModel, TValue>> expression)
{
if(ModelMetadata.FromLambdaExpression(expression, html.ViewData).IsRequired)
return "*";
else
return string.Empty;
}
The problem with the solution from Gregoire and Faxanadu is that the "*" is always displayed, also when the field is validated using the normal validation and you use 'Html.ValidationMessageFor()'.
So if you use the html extension like this:
@Html.EditorFor(model => model.Email)
@Html.RequiredFieldFor(model => model.Email)
@Html.ValidationMessageFor(model => model.Email)
You'll see duplicate * in case the field has validation errors.
I've made this modified extension, based on this which does also check if the field was validated.
private static Type[] RequiredTypes = new Type[] { typeof(CustomRequiredAttribute), typeof(RequiredAttribute) };
/// <summary>
/// Generate a <span class="field-validation-error">*<< element.
///
/// See http://koenluyten.blogspot.com/2011/06/denote-required-fields-in-aspnet-mvc-3.html
/// </summary>
public static MvcHtmlString RequiredFieldFor<TModel, TValue>(this HtmlHelper<TModel> html,
Expression<Func<TModel, TValue>> expression, string validationMessage = "*")
{
// Get the metadata for the model
var metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
string fieldName = metadata.PropertyName;
// Check if the field is required
bool isRequired = metadata
.ContainerType.GetProperty(fieldName)
.GetCustomAttributes(false)
.Count(m => RequiredTypes.Contains(m.GetType())) > 0;
// Check if the field is validated
bool isValidated = html.ViewData.ModelState[fieldName] != null;
// If the field is required and not validated; generate span with an asterix
if (isRequired && !isValidated)
{
var span = new TagBuilder("span");
span.AddCssClass("field-validation-error");
span.SetInnerText(validationMessage);
return MvcHtmlString.Create(span.ToString(TagRenderMode.Normal));
}
return null;
}
If you are getting an "invalid arguments" error when using "ModelMetadata.FromLambdaExpression", make sure you specify a generic type parameter for HtmlHelper. Here is a revised version of Gregoire's solution:
public static string RequiredMarkFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
if (ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData).IsRequired)
return "*";
else
return string.Empty;
}
If you are using full form templated helpers EditorFor and DisplayFor you need to customize your own version of Object.ascx.
Brad Wilson has an awesome blog post which outlines this:
http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-4-custom-object-templates.html
What happens it the IsRequired property on ModelMetadata will be true. Inside Object.ascx:
<%=propertu.IsRequired ? "*" : ""%>
If your not using templated helpers you'd have to write your own html helper. What do your views look like?
I now the question is a little old, but I am working to an unobstrusive solution using just jquery.
My goal is to get all inputs marked with data-val-required attribute, and then set its label elementes markeds with attribute for
Here is the sample jquery code:
$('[data-val-required]').each(function() {
var $label = $('label[for=' + this.name + ']');
//from here we can manipulate the label element
$label.css('font-weight', 'bold');
$label.text($label.text() + ' *');
});
精彩评论