Hacking jQuery-Validate in ASP.NET MVC
You'll remember from my last post that I've been working on a small order-entry program in ASP.NET MVC. This is my first "from scratch" ASP.NET MVC application, so I've been learning some MVC and jQuery tricks along the way.
Here's a partial screenshot of the "new order" screen to refresh your memory:
You'll notice that each silo has a "capacity", and I wanted to be able to limit the item quantity to that value. No sense in allowing a farm to order more feed than will fit into the silo!
ASP.NET MVC's support for data annotations (in the form of attributes) to enable validation is very funky. I can mark my Quantity
property up like this:
[Range(0, 99)]
public int Quantity { get; set; }
... and the generated HTML will automatically apply an error to the text input when the user types a negative value or one above 99. The markup ends up looking something like this:
<input data-val-range="Value must be between 0 and 99."
data-val-range-max="99" data-val-range-min="0" ... />
I can't remember the exact error message, but you get the idea.
This is all well and good for values that apply at compile time, but each one of my order items should have its "data-val-range-max" value set to the capacity of the silo, and I can't do that with a [Range]
attribute.
I could have defined my own custom validation class and corresponding .js file to enable this sort of validation logic, but for now I have found a much easier way. In the Razor view that renders the form, I found the line the spits out the text input, and changed it to this:
@Html.TextBoxFor(m => m.Items[i].Quantity,
new
{
maxlength = 2,
data_val_range_min = 0,
data_val_range_max = item.Silo.Capacity,
data_val_range = "Quantity must be between 0 and " + item.Silo.Capacity + "."
})
So I'm still telling Razor to generate a text input box for my "Quantity" property, but I'm adding some custom attributes to the generated HTML. It looks like this now:
<input data-val="true" data-val-range="Quantity must be between 0 and 12."
data-val-range-max="12" data-val-range-min="0"... />
In this case, the silo's capacity is 12 tonne, and so the Quantity input associated with that silo has had its maximum value set to 12 too.
This gives me client-side validation of each order item's quantity without having to define my own custom validation .js code! Of course I've mirrored the logic in C#, so if the form is somehow posted with invalid data it will still get rejected. Still, this simple workaround saved me quite a lot of time, and I hope it helps you too.
Trackbacks
- Dew Drop – April 15, 2011 | Alvin Ashcraft's Morning Dew | http://www.alvinashcraft.com/2011/04/15/dew-drop-april-15-2011/
- Hacking jQuery-Validate in ASP.NET MVC - Matt... | .NET and ASP.NET MVC | Syngu | http://www.syngu.com/development/3104831727/hacking-jquery-validate-in-asp.net-mvc-matt-hamilton/
- Hacking jQuery-Validate in ASP.NET MVC « Mas-Tool's Favorites | http://mas-tool.com/?p=2762
No new comments are allowed on this post.
Comments
nachid
This is very smart.
Thank you for sharing this idea
I am , however, wondering if you are still using this line of code
In this case, validation attributes should override your @Html.TextBox attributes.
Matt Hamilton
Hi nachid,
No, I don't have the attribute on the property itself anymore. You might be right - I'm not sure which one "wins" in this case.
Andrey
Mixing View and Model is a bad idea. In this case (if you can't use attributes on Model), you can implement ModelValidator. It's a little bit harder, but allows you to keep Model and View separated.
sridhar chinta
lol.. you are awesome. i was just looking for this since half hour
rolphus
Thanks for this!
The MVC3 design limitiation of only allowing model annotations to be design-time constants is constantly irritating to me, and this little hack makes decent client-side validation a hell of a lot easier.
I keep being tempted to spend some proper time rolling my own truly dynamic data validation system, but, as usual, time constraints and the need to get a product shipped override that.