maxlength attribute of a text box from the DataAnnotations StringLength in Asp.Net MVC
If you're using unobtrusive validation, you can handle this client side as well:
$(document).ready(function ()
{
$("input[data-val-length-max]").each(function ()
{
var $this = $(this);
var data = $this.data();
$this.attr("maxlength", data.valLengthMax);
});
});
I am not aware of any way to achieve this without resorting to reflection. You could write a helper method:
public static MvcHtmlString CustomTextBoxFor<TModel, TProperty>(
this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression,
object htmlAttributes
)
{
var member = expression.Body as MemberExpression;
var stringLength = member.Member
.GetCustomAttributes(typeof(StringLengthAttribute), false)
.FirstOrDefault() as StringLengthAttribute;
var attributes = (IDictionary<string, object>)new RouteValueDictionary(htmlAttributes);
if (stringLength != null)
{
attributes.Add("maxlength", stringLength.MaximumLength);
}
return htmlHelper.TextBoxFor(expression, attributes);
}
which you could use like this:
<%= Html.CustomTextBoxFor(model => model.Address1, new { @class = "text long" })%>
I use the CustomModelMetaDataProvider to achieve this
Step 1. Add New CustomModelMetadataProvider class
public class CustomModelMetadataProvider : DataAnnotationsModelMetadataProvider
{
protected override ModelMetadata CreateMetadata(
IEnumerable<Attribute> attributes,
Type containerType,
Func<object> modelAccessor,
Type modelType,
string propertyName)
{
ModelMetadata metadata = base.CreateMetadata(attributes,
containerType,
modelAccessor,
modelType,
propertyName);
//Add MaximumLength to metadata.AdditionalValues collection
var stringLengthAttribute = attributes.OfType<StringLengthAttribute>().FirstOrDefault();
if (stringLengthAttribute != null)
metadata.AdditionalValues.Add("MaxLength", stringLengthAttribute.MaximumLength);
return metadata;
}
}
Step 2. In Global.asax Register the CustomModelMetadataProvider
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ModelMetadataProviders.Current = new CustomModelMetadataProvider();
}
Step 3. In Views/Shared/EditorTemplates Add a partial view called String.ascx
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%if (!ViewData.ModelMetadata.AdditionalValues.ContainsKey("MaxLength")) { %>
<%: Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = "text-box single-line" }) %>
<% } else {
int maxLength = (int)ViewData.ModelMetadata.AdditionalValues["MaxLength"];
%>
<%: Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = "text-box single-line", MaxLength = maxLength })%>
<% } %>
Done...
Edit. The Step 3 can start to get ugly if you want to add more stuff to the textbox. If this is your case you can do the following:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%
IDictionary<string, object> Attributes = new Dictionary<string, object>();
if (ViewData.ModelMetadata.AdditionalValues.ContainsKey("MaxLength")) {
Attributes.Add("MaxLength", (int)ViewData.ModelMetadata.AdditionalValues["MaxLength"]);
}
if (ViewData.ContainsKey("style")) {
Attributes.Add("style", (string)ViewData["style"]);
}
if (ViewData.ContainsKey("title")) {
Attributes.Add("title", (string)ViewData["title"]);
}
%>
<%: Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, Attributes)%>