Say I have a model like this
public class User
{
[Required]
[StringLength(14, ErrorMessage = "Can only be 14 characters long")]
public string UserName;
}
I want to create a Html helper like this:
@Html.ValidatableEditorFor(m => m.UserName)
so that it spits out a text field with the correct format for jQuery Vaidation plugin to be able to validate, like this:
<input type="text" class="required" maxlength="14" />
From my research, it seems that there is no way to iterate over all the data annotations in a MetaDataModel so that I can check to see which one's are applicable to jQuery Validation.
How I envision it working in pseudo code:
var tag = new TagBuilder("input");
tag.mergeAttribute("type", "text");
foreach(var attribute in metadata.attributes)
{
CheckForValidatableAttribute(attribute, tag);
}
...
private void CheckForValidatableAttribute(DataAnnotation attribute, TagBuilder tag)
{
switch(attribute.type)
{
case Required:
tag.addClass("required");
break;
case StringLength
tag.mergeAttribute("maxlength", attribute.value)
break;
}
}
How could I go about achieving a helper like this? I want it to work on data annotations so that I don't have to duplicate the validation literals.
For instance, the current Html helpers like TextEditorFor do append validatable attributes to their output fields. How does it do this, and how can I make my own implementation?
Cheers
You may use this simple condition:
if(attribute.Type is ValidationAttribute)
{
string className = attribute.Type.Name.Replace("Attribute", "").ToLower();
}
Define an Html helper:
public static MvcHtmlString ValidationEditorFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression)
{
....
}
Create this helper method:
private static string GetPropertyNameFromExpression<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
MemberExpression memberExpression = expression.Body as MemberExpression;
if (memberExpression == null)
throw new InvalidOperationException("Not a memberExpression");
if (!(memberExpression.Member is PropertyInfo))
throw new InvalidOperationException("Not a property");
return memberExpression.Member.Name;
}
Now use this in ValidationEditorFor
:
var propertyName = GetPropertyNameFromExpression(htmlHelper, expression);
var propertyType = typeof(TModel).GetProperties().Where(x=>x.Name == propertyName).First().PropertyType;
var attributes = propertyType.GetCustomAttributes(true).OfType<ValidationAttribute>();
Now you can check the attributes.... rest is easy.