asp.net mvc client side validation -
i've been tinkering client side validation features in asp.net mvc after reading scottgu's blog post on subject. it's pretty easy use system.componentmodel.dataannotations attributes this:
[required(errormessage = "you must specify reason")] public string reasontext { get; set; }
... happens if need little more complex. if have address class postalcode , countrycode field. want validate postal code against different regex each country. [0-9]{5} works usa, need different 1 canada.
i got around rolling own validationservice class takes modelstate property of controller , validates accordingly. works great on server side doesn't work fancy new client side validation.
in webforms use javascript-emitting controls requiredfieldvalidator or comparevalidator easy stuff , use customvalidator complex rules. way have validation logic in 1 place, , benefit of rapid javascript validation simple stuff (90% of time) while still security of server side validation backstop.
what equivalent approach in mvc?
edit: assumes using mvc 3. unfortunately code in vb.net since that's have use @ work.
in order make work nicely new unobtrusive validation there few things have do. powered through them couple of weeks ago.
first, create custom attribute class inherits validationattribute
. simple requiredif attribute class below:
imports system.componentmodel imports system.componentmodel.dataannotations <attributeusage(attributetargets.field or attributetargets.property, allowmultiple:=false, inherited:=false)> _ public notinheritable class requiredifattribute inherits validationattribute private const _defaulterrormessage string = "'{0}' required." private readonly _dependentproperty string private readonly _targetvalues object() public sub new(dependentproperty string, targetvalues object()) mybase.new(_defaulterrormessage) _dependentproperty = dependentproperty _targetvalues = targetvalues end sub public sub new(dependentproperty string, targetvalues object(), errormessage string) mybase.new(errormessage) _dependentproperty = dependentproperty _targetvalues = targetvalues end sub public readonly property dependentproperty() string return _dependentproperty end end property public readonly property targetvalues() object() return _targetvalues end end property public overrides function formaterrormessage(name string) string return string.format(globalization.cultureinfo.currentuiculture, errormessagestring, name) end function protected overrides function isvalid(value object, context validationcontext) validationresult ' find other property need compare using reflection dim propertyvalue = context.objecttype.getproperty(dependentproperty).getvalue(context.objectinstance, nothing).tostring() dim match = targetvalues.singleordefault(function(t) t.tostring().tolower() = propertyvalue.tolower()) if match isnot nothing andalso value nothing return new validationresult(formaterrormessage(context.displayname)) end if return nothing end function end class
next, need implement validator class. class responsible letting mvc know client validation rules required unobtrusive validation library work.
public class requiredifvalidator inherits dataannotationsmodelvalidator(of requiredifattribute) public sub new(metadata modelmetadata, context controllercontext, attribute requiredifattribute) mybase.new(metadata, context, attribute) end sub public overrides function getclientvalidationrules() ienumerable(of modelclientvalidationrule) dim rule new modelclientvalidationrule() {.errormessage = errormessage, .validationtype = "requiredif"} rule.validationparameters("dependentproperty") = attribute.dependentproperty.replace("."c, htmlhelper.idattributedotreplacement) dim first boolean = true dim arraystring new stringbuilder() each param in attribute.targetvalues if first first = false else arraystring.append(",") end if arraystring.append(param.tostring()) next rule.validationparameters("targetvalues") = arraystring.tostring() return new modelclientvalidationrule() {rule} end function end class
now can register in application start method of global.asax
:
dataannotationsmodelvalidatorprovider.registeradapter(gettype(requiredifattribute), gettype(requiredifvalidator))
this gets 90% of way there. need tell jquery validate , ms's unobtrusive validation layer how read new attributes:
/// <reference path="jquery-1.4.1-vsdoc.js" /> /// <reference path="jquery.validate-vsdoc.js" /> /* javascript custom unobtrusive validation ==================================================== */ (function ($) { // adds custom "requiredif" validator jquery validate plugin $.validator.addmethod('requiredif', function (value, element, params) { // "value" variable must not empty if dependent value matches // 1 of target values var dependentval = $('#' + params['dependentproperty']).val().trim().tolowercase(); var targetvalues = params['targetvalues'].split(','); // loop through target values (i = 0; < targetvalues.length; i++) { if (dependentval == targetvalues[i].tolowercase()) { return $.trim(value).length > 0; } } return true; }, 'not used'); // tells ms unobtrusive validation layer how read // html 5 attributes output custom "requiredif" validator $.validator.unobtrusive.adapters.add('requiredif', ['dependentproperty', 'targetvalues'], function (options) { options.rules['requiredif'] = options.params; if (options.message) { options.messages['requiredif'] = options.message; } }); } (jquery));
hope helps, real pain working.
Comments
Post a Comment