This is part 2 of the series “Understanding Unobtrusive Validation in ASP.Net MVC”
1. The jQuery validate plugin works from the inside2. Understanding Html-code generated by unobtrusive validation in ASP.Net MVC
3. Internal work of the jQuery validate unobtrusive plugin in ASP.Net MVC.What we will discuss in this article:
')
- Unobtrusive javascript idea
- The difference between normal and unobtrusive validation
- Understanding of unobtrusive validation:
- Elements of "input", the rules of their validation and how they work
- Validation messages and how they work in unobtrusive validation.
The basic idea of unobtrusive javascript
Microsoft introduced the first validation module in the first version of MVC. The module was improved with each version, and turned into unobtrusive validation in ASP.Net MVC 3.
In short, even in modern JavaScript, which we write mainly in a separate js file, we sometimes need data related to Html, and therefore we write the metadata of JavaScript objects inside the Html page. We call the function from the js file to which we pass the object metadata on the page.
One of the goals of unobtrusive javascript is to separate javascript from html markup.
You can read more about this
here (the author refers us to an article about unobtrusive JavaScript in English-language Wikipedia, approx. Translator)
The difference between normal and unobtrusive validation.
Below is the model code and Html markup generated using MVC 2 validation and MVC 3 unobtrusive validation.
Our model
C #
public class ValidationModel { [Required] public string FirstName { get; set; } [Required, StringLength(60)] public string LastName { get; set; } [Range(1, 130)] public int Age { get; set; } }
Representation in MVC 2 using html helper s
Html
<label for="FirstName">FirstName</label> <input id="FirstName" class="text-box single-line" type="text" name="FirstName" value="" /> <span id="FirstName_validationMessage" class="field-validation-valid"></span> <label for="LastName">LastName</label> <input id="LastName" class="text-box single-line" type="text" name="LastName" value="" /> <span id="LastName_validationMessage" class="field-validation-valid"></span> <label for="Age">Age</label> <input id="Age" class="text-box single-line" type="text" name="Age" value="" /> <span id="Age_validationMessage" class="field-validation-valid"></span> <script type="text/javascript">// <![CDATA[ if (!window.mvcClientValidationMetadata) { window.mvcClientValidationMetadata = []; } window.mvcClientValidationMetadata.push({"Fields":[{"FieldName":"FirstName","ReplaceValidationMessageContents":true,"ValidationMessageId":"FirstName_validationMessage","ValidationRules":[{"ErrorMessage":"The FirstName field is required.","ValidationParameters":{},"ValidationType":"required"}]},{"FieldName":"LastName","ReplaceValidationMessageContents":true,"ValidationMessageId":"LastName_validationMessage","ValidationRules":[{"ErrorMessage":"The LastName field is required.","ValidationParameters":{},"ValidationType":"required"},{"ErrorMessage":"The field LastName must be a string with a maximum length of 60.","ValidationParameters":{"max":60},"ValidationType":"length"}]},{"FieldName":"Age","ReplaceValidationMessageContents":true,"ValidationMessageId":"Age_validationMessage","ValidationRules":[{"ErrorMessage":"The field Age must be between 1 and 130.","ValidationParameters":{"min":1,"max":130},"ValidationType":"range"},{"ErrorMessage":"The Age field is required.","ValidationParameters":{},"ValidationType":"required"},{"ErrorMessage":"The field Age must be a number.","ValidationParameters":{},"ValidationType":"number"}]}],"FormId":"form0","ReplaceValidationSummary":true,"ValidationSummaryId":"validationSummary"}); // ]]></script>
Representation in MVC 3 using html helper-s and unobtrusive validation
Html
<label for="FirstName">FirstName</label> <input id="FirstName" class="text-box single-line" type="text" name="FirstName" value="" data-val="true" data-val-required="The FirstName field is required." /> <label for="LastName">LastName</label> <input id="LastName" class="text-box single-line" type="text" name="LastName" value="" data-val="true" data-val-length="The field LastName must be a string with a maximum length of 60." data-val-length-max="60" data-val-required="The LastName field is required." /> <label for="Age">Age</label> <input id="Age" class="text-box single-line" type="text" name="Age" value="" data-val="true" data-val-number="The field Age must be a number." data-val-range="The field Age must be between 1 and 130." data-val-range-max="130" data-val-range-min="1" data-val-required="The Age field is required." />
This code is taken from the
Brad Wilson article
"Unobtrusive Client Validation in ASP.NET MVC 3".As we can see, the “input” Html elements have no idea what validation rules are applied to them. There is only one large JavaScript object containing the validation information applied to each page element.
On the other hand, if we look at the “input” elements generated by MVC 3, we will see that they contain more metadata. All information necessary for validation is contained in the data-* attributes. There is no need for a huge JavaScript object.
Understanding Unobtrusive Validation
1. The “input” elements, their validation rules and how they work
So let's find out what happens with the “data- *” attributes.
MVC creates data- * attributes based on validation rules.
jquery.validate.unobtrusive reads the rules and converts them to a path.
After the unobtrusive validation has transformed these rules, it will call the “validate ()” method and pass an array of rules with their settings to validate them.
There are three parts to any unobtrusive rule for any Html element:
- data-val = ”true” is just a flag denoting that an unobtrusive validation is attached to the element.
- data-val-rulename = ”message” - does two things. The “data-val-rulename” part indicates the name of the rule, and the message text contains the validation message.
- data-val-rulename-additional values = ”value” to add additional values needed by the validation rule to complete validation. (For example, validation of the "range" of a range of values when the value should be less than some value and more than another)
Let us consider in more detail the generated element “input” and explain the attributes “data- *”.
<input id="Name" class="ignore" type="text" name="Name" value="" data-val="true" data-val-required="*" data-val-atleastonerequired="Enter at least Name, Email or Lastname" data-val-atleastonerequired-attributes="Email,LName" />
Two rules apply to the item. One is the built-in attribute “required”, and the other is its own, called “atleastonerequired”.
When the user does not enter any data and clicks "Submit Form", "*" appears as a validation message that indicates that the element is required.
If the user violates the “atleastonerequired” rule, his validation message will appear.
2. Validation messages and how they work in unobtrusive validation.
Let's start with an example.
<input id="FirstName" class="text-box single-line" type="text" name="FirstName" value="" data-val="true" data-val-required="The FirstName field is required." /> <span data-valmsg-replace="true" data-valmsg-for="Name" class="field-validation-valid help-inline" />
As we can see, there are two “data- *” elements in the container for the error message.
- “Data-valmsg-for” is the value of the “name” attribute of the “input” element to which the container belongs. Both the input element and the container must be in the same form tag.
- “Data-valmsg-replace” is set to true by default. The difference between true and false values is the following: if set to true, the error message in the container will change depending on which validation rule was violated, if false, it will be constant and the content will not change, only the class with “ valid to invalid.
If one of the validation rules is violated, the value of the “class” attribute will contain “field-validation-error”, and if not, then “field-validation-valid”.
Translation of Nadeem Khedr article
"Understand the Html generated by the unobtrusive validation in Asp.net MVC"update 01.06.13: added links to other posts in the series