door: Maarten Sikkema - gepubliceerd op 13-5-2013
[Update 29-9-2013: We published a NuGet package Bootstrap.MVC.EditorTemplates containing the controls and validation setup as described in this post. Read more in this follow-up post.]
ASP.NET MVC provides built-in support for data validation. The nice thing about it is that this validation can happen both server-side and client-side, and those can be managed from one single place in code. Validation rules are defined by setting attributes on the fields of a Model class, like this:
3132 |
|
There are many different attributes and validation expressions available, including regular expressions. Some examples:
12131415161718192021222324252627282930313233343536373839404142 |
|
In the Cloud Auction project we are using the Twitter Bootstrap framework and several componentsthat come with it. We also use a few additional components that are not part of the standard Bootstrap component set, such as a datepicker and timepicker control. There is a rich ecosystem for additional Bootstrap components and many existent jQuery components have been modified so they look consistent with Bootstrap out of the box, without adding additional styling.
Reusable controls in MVC can be created as a Partial View. A special kind of Partial Views are DisplayTemplates and EditorTemplates. These templates can be applied automatically every time you want to display (or edit) a specific data type or Model, using the Html.DisplayFor and Html.EditorFor helpers. Templates are defined as normal Views that are placed in a subfolder “DisplayTemplates” and “EditorTemplates” under any View folder, (such as Views\Shared or a specific folder where you want to use these templates). MVC has built-in templates for standard data types such as strings, but it is possible to override these and add templates for custom types. By default, MVC uses the type name to search for a matching Editor/DisplayTemplate.
For instance, we use the following template for a string:
21222324252627282930 |
|
Now, to get an edit box for a string on a page, I can do that in just one line in the view:
1 |
|
And it will render like this, complete with label, with a nice Bootstrap design:
Because the Title field has an attribute “required”, there should be an error when we leave it empty. And indeed:
This error message appears immediately when we clear the input field. How does this work? Look at the DOM that was generated by the control:
123456789 |
|
The Html.TextBox() has added a “data-val-required” attribute to the input box. The Html.ValidationMessageFor() has added the error message that was declared in a [Required] attribute on the Title field in the Auction Domain Model.
All data-val-* attributes are picked up by two javascript files that we included on this page (using a bundle):
jquery.validate.js
jquery.validate.unobtrusive.js
site/validation.js
jquery.validate.unobtrusive.js
site/validation.js
The site validation.js script initializes jquery validation to work in a bootstrap based forms design:
12345678 |
|
These jquery plugins will recognize the attributes and do client-side evaluation of the validation rules. If an error is detected, they will call our highlight function that sets an “error” attribute on the containing <div class=”control-group”> and place the error message inside the <span> element. The bootstrap styling will react to the error class by highlighting all the elements in the control group in red. Also the submit of data will be blocked as long as there are errors.
So our client-side validation works. That very user friendly, but of course we can never trust this for our business logic on the server. A malicious user might disable or bypass javascript validation and can post anything to the server. Before we accept any values posted by a user, we have to do server-side validation. The Controller receiving the data is here:
7576777879808182838485 |
|
Validation is checked with the ModelState.IsValid property. The MVC framework automatically applies the validation rules, and sets this property to false if it finds invalid data. To test this out, we can disable javascript and post an empty value for the Title field. Now we see a page refresh happening, the same page returns with an error message:
This looks exactly the same as before, when we created a client-side validation error. Internally however, something else has happened because now the server has rendered the error. The rendered markup is almost, but not exactly the same:
1234567 |
|
The ValidationErrorFor is just a small Helper function that is used to additionally set the class=”error” on the control-group (just like the client-side validation does) so that bootstrap styling will highlight the whole control by making it red.
22232425262728 |
|
The nice thing about all this is that now both client-side and server-side validation rules are set declaratively, using attributes on the Model. The MVC framework, together with the jquery validation javascript plugin are able to validate the Model data both client-side and server-side. By creating EditorTemplates for all the data types that we use, we can create reusable and good-looking forms using one-liners for every data field on the form.
This concept becomes even more powerful when used with more complex data types. For instance, for Date fields, we use a datepicker control and for TimeSpan fields a timepicker. When I looked for a datepicker and timepicker components for Boostrap, I found many. The biggest problem is finding the best one. Here is an EditorTemplate for a combined Date and Time field, for which I created a special class that takes one DateTime value and maps that to a separate Date and Time property, that can easily be mapped to two html controls in a single EditorTemplate. Click the gist link to also see the way the ViewModel is subclasses from the Domain Model.
123456789101112 |
|
Once you have found good controls, set up the javascript and created EditorTemplates, using them becomes extremely simple and the result look quite nice.
No comments:
Post a Comment