1

I am trying MVC's datatype attributes, and just created a simple scenario like the following:

The View:

@model MVC4.Models.Model

@{
    ViewBag.Title = "DataTypeAttribute";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>

<h2>DataTypeAttribute</h2>


@using (Html.BeginForm("SubmitData", "Home"))
{
    <div>
        @Html.ValidationSummary()
    </div>

    @Html.EditorFor(m => m.Email)
    <br />
    <br />
    @Html.EditorFor(m => m.PostalCode)

    <br />
    <br />
    @Html.EditorFor(m => m.TextOnly)
    <br />
    <br />

    <button type="submit">Submit</button>
}

The Model:

public class Model
{
    [DataType(DataType.EmailAddress)]

    [Required]
    //[EmailAddress]
    public string Email { get; set; }

    [DataType(DataType.PostalCode)]
    public string PostalCode { get; set; }


    public string TextOnly { get; set; }
}

"SubmitData" is just a controller that, returns View(..., model) if ModelState.IsValid is false.

Although posts like this do a good job in tackling the differences between Html.TextBoxFor and Html.EditorFor, I could not find an answer as to why validation for the datatype EmailAddress will not work when using TextBoxFor. I did find people mentioning TextBoxFor does not take metadata into account, while EditorFor does.

But does this make sense ? So TextBoxFor does not offer support for client validations ?!

I wonder what is the reason for the difference between the two ?

Community
  • 1
  • 1
Veverke
  • 9,208
  • 4
  • 51
  • 95
  • Summarizing the answer: the new input types introduced with HTML 5, such as add automatic validation. TextBoxFor always generate inputs of type 'text', and therefore no built in validation is generated. On the other hand, EditorFor takes model fields metadata (data annotations) into account when generating the html for them, so a field marked with "DataType(DataType.EmailAddress)" will generate an input type='email', and thus the new built-in HTML 5 validation along with it. – Veverke Jun 25 '15 at 09:45

1 Answers1

3

TextBoxFor() does work with validations.

[DataType(DataType.EmailAddress)] is not a validation attribute. Its an attribute that determines the type of input to display by setting the type attribute in the rendered html. For example <input type="text" ..>, <input type="date" ..>, <input type="email" ..> in order to render the browsers implementation of a HTML4 datepicker, email input etc.. It works only for EditorFor() because TextBoxFor() as its name suggest generates and input with type="text"

If you want validation for an email address, then you use the [EmailAddress] attribute on your property.

[Required]
[EmailAddress]
public string Email { get; set; }

Edit (further to the comments)

One of the features of HTML5 is the ability to validate user data without relying on scripts. One such form of browser validation is using the type attribute. The use of [DataType(DataType.EmailAddress)] on a property that is rendered with @Html.EditorFor() adds type="email" to the input element. From the MDN documentation

email: The element represents one email address. Line breaks are automatically stripped from the input value. An invalid email address can be set, but the input field will only satisfy its constraints if the email address satisfies the ABNF production 1*( atext / "." ) "@" ldh-str 1*( "." ldh-str ) where atext is defined in RFC 5322 section 3.2.3, and ldh-str is defined in RFC 1034 section 3.5.

If your are currently seeing a validation error message associated with the property, and you have not added the [EmailAddress] attribute, then it means that jquery.validate.js is not loaded and you are seeing the browsers error message associated with type="email".

When jquery.validate.js is loaded (correctly), the novalidate="novalidate" attribute is added to the form element, which specifies that form is not to be validated (using the HTML5 validation) when submitted. The relevant code from jquery.validate.js is (approx line 35)

// Add novalidate tag if HTML5.
this.attr('novalidate', 'novalidate');

This is added to prevent possible confusion between error messages displayed by browser validation and jquery unobtrusive validation.

As to why DataTypeAttribute attribute inherits ValidationAttribute when it does not actually do validation, from Brad Wilson himself in this answer

The reason it derives from ValidationAttribute is so that you could create a new custom data type class, which was both a DataType and a Validation, all wrapped up into one. It's an unfortunate side-effect of .NET not allowing multiple inheritance.

Community
  • 1
  • 1
  • At first your answer looked very promising, but after some testing I can say: 1) using [EmailAddress] and DataType(EmailAddress) has exactly the same effect. In other words, you say DataType is not a validation attribute, but it does add validation in this case. 2) using DataType(Text) or PostalCode create input which type is "text" in both cases, and look the same... if validations are not at stake, what's the point in using them ? In this case we know beforehand we will end up with text inputs anyway... – Veverke Jun 23 '15 at 12:08
  • No it does not. I see the only script you have is `jquery.validate.unobtrusive.min.js` which on its own will do absolutely nothing. You need `jquery.js` and `jquery.validate.js` and `jquery.validate.unobtrusive.js` (in that order). And I also suggest you use `@Html.ValidationMessageFor()` associated with each control and change `@Html.ValidationSummary()` to `@Html.ValidationSummary(true)` –  Jun 23 '15 at 12:10
  • You should also inspect the html you generate. Validation attributes add various `data-val` attributes to the rendered html. All the `[DataType]` attribute does id set the appropriate `type` attribute –  Jun 23 '15 at 12:13
  • what about DataTypes such as Text and PostalCode, which render input which types are text ? What is the purpose of such datatypes then? – Veverke Jun 23 '15 at 12:16
  • And from [this link](http://www.asp.net/mvc/overview/older-versions/getting-started-with-aspnet-mvc4/adding-validation-to-the-model) which I suggest you study. _The DataType attributes are not validation attributes, they are used to tell the view engine how to render the HTML. In the example above, the DataType.Date attribute displays the movie dates as dates only, without time. For example, the following DataType attributes don't validate the format of the data:_ –  Jun 23 '15 at 12:17
  • `DataType.Text` is just the standard input - `` (identical to using `TextBoxFor()`). The others will depend on the browser your using and if they have been implemented by the browser. For example, `DataType.Time` is not implemented at all in FireFox yet –  Jun 23 '15 at 12:20
  • You are saying that DataType attributes are related to display format only. Ok. Regarding DataType(EmailAdress) not adding validation... this is strange... can you run a test using DataType(EmailAddresses) and see if you do not get validations ? Perhaps the validation occurs because there is some validation that is triggered behind the scenes automatically for inputs of type "email" ? – Veverke Jun 23 '15 at 12:20
  • If your getting validations with just `DataType.EmailAddresses` its because client side validation is not implemented and its then using the browsers implementation. –  Jun 23 '15 at 12:22
  • But is client side validation enabled? Read the link a gave you. You still have a lot to learn :). And compare the rendered html before and after you add `[EmailAddress]` to the property to see the difference –  Jun 23 '15 at 12:29
  • I will, I was busy here with some meetings, will get back to this tomorrow and let you know. Thanks for helping – Veverke Jun 23 '15 at 16:10
  • I went over the article you mention, yesterday. Right, it clearly states the DataType attribute is *not* a validation attribute. Why then did microsoft made the DataType attribute inherit from ValidationAttribute? Isn't it conceptually wrong ? By inheriting, DataType can be passed parameters like _ErrorMessageResourceType_ and _ErrorMessageResourceName_, which is misleading, if ultimately DataAttribute has nothing to do with validation, but with display format. – Veverke Jun 25 '15 at 09:47
  • Regarding the validation message I was getting without adding any validation attribute - just by creating an e-mail input type, I know understand that these new input types introduced in HTML 5 add automatic validation - something I did not know. Thanks. – Veverke Jun 25 '15 at 09:47
  • You raise an interesting point about the attribute inheriting `ValidationAttribute`. When I get some time I'll go through the source code and see if there is some obvious reason and let you know - otherwise its probably a question for the developers :) –  Jun 25 '15 at 09:56
  • Can you add info like what I added as a comment summarizing the answer to the question so I mark your post the anser (currently it only partially answers it) – Veverke Jun 25 '15 at 10:21
  • Actually it fully answers it - your extra comment just clarifies your own misunderstanding :) - but I will update with some extra info once I have checked the issue about the inheritance. And note that claiming it includes the _"built-in HTML 5 validation along with it"_ is not necessarily correct. If client side validation is properly enabled in your view, then your form will include the `novalidate="novalidate"` attribute which disables HTML5 validation (jquery validation and HTML5 validation don't play well together) –  Jun 25 '15 at 10:34
  • But then you again leave me with the question "why/where does the validation I see come from, if I specified none?" You say jQuery will add the novalidate attribute, but seems it is not, since I am seeing the styled pop-up validating malformed e-mails, coming from the client side. – Veverke Jun 25 '15 at 10:45