I need to add a prefix to the name of form elements that are rendered within a form. I've created a custom attribute to decorate a property that accepts the name of another property whose value will be used for the name prefix.
public class HtmlElementNamePrefixPropertyAttribute : Attribute {
public string PropertyName { get; set; }
public HtmlElementNamePrefixPropertyAttribute(string propertyName) {
PropertyName = propertyName;
}
}
And my custom ModelMetadataProvider:
public class AddressModelMetadataProvider : 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);
HtmlElementNamePrefixPropertyAttribute nameAttribute = attributes.OfType<HtmlElementNamePrefixPropertyAttribute>().FirstOrDefault();
if (nameAttribute != null) {
ModelMetadata prefixMetadata = ModelMetadataProviders.Current.GetMetadataForProperty(modelAccessor, metadata.ContainerType, nameAttribute.PropertyName);
metadata.PropertyName = string.Format("{0}{1}", prefixMetadata.Model, metadata.PropertyName);
}
return metadata;
}
}
As an example, if I decorate Address1
with HtmlElementNamePrefixAttribute
:
[HtmlElementNamePrefix("AddressType")]
public string Address1 { get; set; }
public AddressType AddressType { get; set; }
And in my view render a textbox for Address1
:
@Html.TextBoxFor(m => m.Address1)
It should render as (assuming that AddressType == AddressType.Home
)
<input name="HomeAddress1" value="123 Street way"/>
I have a few problems:
- I'm not sure how to effect the rendered name HTML attribute from
AddressModelMetadataProvider
or what property inModelMetadata
would allow me to do that. My current attempt was to change thePropertyName
property ofModelMetadata
, but that doesn't have a setter. - If possible, I don't want to create a new HtmlHelper as this attribute could apply to any type of form element that would be rendered in an
Address
. I also don't want to create a string EditorTemplate since this scenario only applies to anAddress
object and its properties.
To give a better understanding of what I'm trying to accomplish and why, let me give a brief explanation of the project and its purpose.
Our application allows users to create "fields". From the end users perspective, "fields" can be a single line textbox, multi line textbox (textarea), chooseMany (which is a group of checkboxes), chooseOne (which is a dropdown), address (which consists of more than one form element and can be of type home, business or other), contact (email, phone, and fax), and others. I've simplified a great deal, but I think this gets the point across.
All this information is stored in the database ("field" values, "field" metadata, which "fields" are on the requested "form", etc.), and at runtime used to configure the "form" the user is requesting (i.e., /forms/123). So the form may have a textbox and an address "field", or maybe a home address "field" and a business address "field". Each "form" is created and configured by an administrative user. These "fields" or rather models, inherit from IDataItem and have their own views (templates) that describe how they should be rendered to the UI.
Because of the dynamic nature of a "form" custom model binding and validation was needed (i.e., custom ValidationAttributes, ValidatorProviders, ModelBinders, etc.). Validation rules and logic are applied dynamically at runtime using custom and standard ValidationAttributes (i.e., RequiredAttribute is used for simple "fields" like a single line textbox or chooseOne). This is done at runtime, because the administrator building the "form" can mark a "field" as required or not (as well as other validation constraints).
Required validation for an address "field" is different, because an address is not considered complete unless all parts of the address are filled out (with the exception of address2 and address3).
For client side validation we're using the standard MVC client validation library, jQuery validate. Here in lies my problem... Error messages are applied by jQuery validate based on the name of the form element. So if address1 is invalid, but there is a home address "field" and a business address "field" on the form then a distinction needs to be made between each form element name, so that the error message can be applied to the correct element. This is the biggest reason why I need to prefix the address form element names with AddressType
.
This is a very long-winded simplified explanation, but I think it relays the purpose of the application and why my problem exists.