Question

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 therefore 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

Was it helpful?

Solution

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;
}

OTHER TIPS

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 &lt;span class="field-validation-error"&gt;*&lt;&lt; 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() + ' *');
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top