Note that there are some explanatory texts on larger screens.

plurals
  1. POData annotations, unobtrusive validation. Min age, max age
    primarykey
    data
    text
    <p>What do I want to achieve:</p> <ol> <li>To show a seperate validation message for failing minimum age check and one for maximum age check</li> <li>To store the minimum and maximum age in one area as integers. Not in js/ validator... only in the model. which I hope to change to look at a config file. </li> <li>For the validation to work with jquery unobtrusive and server side, and to be in one place against the model (and obv some jquery)</li> <li>To be enabled using data annotations</li> <li>I wanted to check against DOB as a datetime, not have the user put in there age as an int. If i did I could have used [Min] notation and [Max] notation for age. It wasn't good enough.</li> <li>Why didn't I use a range notation. I wanted to fire a different validation message for each min fail and max fail. I looked into this and had no look. I'd also have to pass in the range as a datetime and its static or something so I couldn't have done DateTime.Now.AddYears(-90) for instance.</li> </ol> <p>My problems</p> <ol> <li>I'm a noob at MVC, JQuery validation and the whole MVC architecture!</li> <li>What I've come up with works. However, as you can see there is alot repeated code, I'd like to conform to DRY.</li> <li><p>My first hack was to pass in the value that i'm checking against into the validation message. I got around this by doing...</p> <p>[MaximumAgeCheck(90,"You have to be at most {0} to apply")]</p></li> </ol> <p>and inside the validation attribute</p> <pre><code> private readonly int _min; private readonly string _defaultErrorMessage = ""; public MinimumAgeCheck(int min, string defaultErrorMessage) : base(defaultErrorMessage) { _min = min; _defaultErrorMessage = defaultErrorMessage.Replace("{0}", _min.ToString()); } </code></pre> <p>and I used it for instance like so..</p> <pre><code>return new ValidationResult(_defaultErrorMessage); </code></pre> <p><strong>I know this isn't the right way to do it, and wondered what is the best way to do this?</strong></p> <p>Second hack!</p> <p>I'm passing in two validation parameters which I want to be able to access in the jQuery.validator.addMethod... method.</p> <p>I tried to access these parameters by doing the following... params.[thevalueiadded], params[0]... etc, I even logged out params into console.log but it never showed me all the params, only the first value as a string!</p> <p>My work around was to store the javascript variables at the top and load them from the adapters.add.</p> <p>I'm probabily making little sense so here is the code, that works...I warn you, it is messy!</p> <p><strong>Model property and data annotation</strong></p> <pre><code>[Required(ErrorMessage = "Date of birth required")] [Display(Name = "Date of Birth")] [DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}")] [DataType(DataType.DateTime, ErrorMessage = "Date of birth should be in dd/mm/yyyy format")] [MinimumAgeCheck(18,"You have to be at least {0} to apply")] [MaximumAgeCheck(90,"You have to be at most {0} to apply")] public DateTime? DateOfBirth { get; set; } </code></pre> <p><strong>Minimum Age Check and Maximum age check</strong></p> <p><em>validation attributes</em> </p> <pre><code>public class MinimumAgeCheck : ValidationAttribute, IClientValidatable { private readonly int _min; private readonly string _defaultErrorMessage = ""; public MinimumAgeCheck(int min, string defaultErrorMessage) : base(defaultErrorMessage) { _min = min; _defaultErrorMessage = defaultErrorMessage.Replace("{0}", _min.ToString()); } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { DateTime dtV = (DateTime)value; long lTicks = DateTime.Now.Ticks - dtV.Ticks; DateTime dtAge = new DateTime(lTicks); if (!(dtAge.Year &gt;= _min &amp;&amp; dtAge.Year &lt;= 30)) { return new ValidationResult(_defaultErrorMessage); } return ValidationResult.Success; } public override string FormatErrorMessage(string name) { return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString, _min); } public IEnumerable&lt;ModelClientValidationRule&gt; GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { ModelClientValidationRule mcvrTwo = new ModelClientValidationRule(); mcvrTwo.ValidationType = "checkminimumage"; mcvrTwo.ErrorMessage = _defaultErrorMessage; mcvrTwo.ValidationParameters.Add("todaysdate", DateTime.Now.ToString("dd/MM/yyyy")); mcvrTwo.ValidationParameters.Add("lowerage", _min.ToString()); return new List&lt;ModelClientValidationRule&gt; { mcvrTwo }; } } public class MaximumAgeCheck : ValidationAttribute, IClientValidatable { private readonly int Max; private readonly string _defaultErrorMessage = ""; public MaximumAgeCheck(int max, string defaultErrorMessage) : base(defaultErrorMessage) { Max = max; _defaultErrorMessage = defaultErrorMessage.Replace("{0}", Max.ToString()); } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { DateTime dtV = (DateTime)value; long lTicks = DateTime.Now.Ticks - dtV.Ticks; DateTime dtAge = new DateTime(lTicks); if (!(dtAge.Year &gt;= Max &amp;&amp; dtAge.Year &lt;= 30)) { return new ValidationResult(_defaultErrorMessage); } return ValidationResult.Success; } public override string FormatErrorMessage(string name) { return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,Max); } public IEnumerable&lt;ModelClientValidationRule&gt; GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { ModelClientValidationRule mcvrTwo = new ModelClientValidationRule(); mcvrTwo.ValidationType = "checkmaximumage"; mcvrTwo.ErrorMessage = _defaultErrorMessage; mcvrTwo.ValidationParameters.Add("todaysdate", DateTime.Now.ToString("dd/MM/yyyy")); mcvrTwo.ValidationParameters.Add("upperage", Max.ToString()); return new List&lt;ModelClientValidationRule&gt; { mcvrTwo }; } } </code></pre> <p><strong>The Jquery</strong></p> <pre><code>(function ($) { var mintodaysDateVal; var maxtodaysDateVal; var lowerageVal; var upperageVal; jQuery.validator.unobtrusive.adapters.add("checkminimumage", ['lowerage', 'todaysdate', 'upperage'], function (options) { options.rules["checkminimumage"] = options.params; mintodaysDateVal = options.params.todaysdate; lowerageVal = options.params.lowerage; options.messages["checkminimumage"] = options.message; }); jQuery.validator.addMethod("checkminimumage", function (value, element, params) { var currDate = mintodaysDateVal; var sdoc = currDate.split('/'); var dobDate = value; var sdob = dobDate.split('/'); //pass year,month,date in new Date object. var vDOB = new Date(sdob[2], sdob[1] - 1, sdob[0]); var vDOC = new Date(sdoc[2], sdoc[1] - 1, sdoc[0]); //getAge user define function to calculate age. var vYrs = getAge(vDOB, vDOC); var result = false; if (vYrs &gt;= lowerageVal) { result = true; } return result; }); jQuery.validator.unobtrusive.adapters.add("checkmaximumage", ['lowerage', 'todaysdate', 'upperage'], function (options) { options.rules["checkmaximumage"] = options.params; maxtodaysDateVal = options.params.todaysdate; upperageVal = options.params.upperage; options.messages["checkmaximumage"] = options.message; }); jQuery.validator.addMethod("checkmaximumage", function (value, element, params) { var currDate = maxtodaysDateVal; var sdoc = currDate.split('/'); var dobDate = value; var sdob = dobDate.split('/'); var vDOB = new Date(sdob[2], sdob[1] - 1, sdob[0]); var vDOC = new Date(sdoc[2], sdoc[1] - 1, sdoc[0]); var vYrs = getAge(vDOB, vDOC); var result = false; if (vYrs &lt;= upperageVal) { result = true; } return result; }); function getAge(oldDate, currDate) { return currDate.getFullYear() - oldDate.getFullYear(); } } (jQuery)); </code></pre> <p>I hope this makes sense, I've read it over and its quite garbled... so i'll be happy to answer any comments.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload