I want to be able to validate that a birthdate entered is 18 or older. I have searched and found numerous posts about this. However, I don't understand
1) Why MS didn't build this into MVC3 like the other validations such as string, email, password, etc.
2) why when I get the javascript in place to make the dates correctly validate, the other unobtrustive js doesn't work any more.
I want to have client side validation before submit yet, dates doesn't seem to work well with this. All the rest does.
Am I missing something ?
some code I've tried in my model
#1) [Display(Name = "Date of Birth (must be at least 18) ")]
public DateTime Birthdate
{
get
{
if ((SelectedBMonth != "0") && (SelectedBday != "0") && (SelectedBYear != "0"))
return DateTime.Parse(SelectedBMonth + "/" + SelectedBday + "/" + SelectedBYear);
else
return DateTime.MinValue;
}
}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (Birthdate.Date > DateTime.Today.AddYears(-18))
yield return new ValidationResult("You must be at least 18 years old to register", new[] { "Birthdate" });
}
#2)
[Required]
[CustomValidation(typeof(RegisterModel), "ValidateDOBDate")]
[DataType(DataType.Date)]
[Display(Name = "Date of Birth")]
public DateTime DateOfBirth { get; set; }
public static ValidationResult ValidateDOBDate(DateTime DateOfBirthtovalidate) { if (DateOfBirthtovalidate.Date > DateTime.Now.AddYears(-18)) { return new ValidationResult("User should be atleast 18 years old."); } if (DateOfBirthtovalidate.Date < DateTime.Now.AddYears(-150)) { return new ValidationResult("Please put a valid date"); } return ValidationResult.Success; }
#3)
public class DateofBirthAttribute : ValidationAttribute, IClientValidatable
{
public override bool IsValid(object value)
{
if (value == null || (DateTime)value < DateTime.Today.AddYears(-18))
return false;
return true;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationRule
{
ErrorMessage = this.ErrorMessage,
ValidationType = "dateofbirth"
};
}
}
[Required]
[Display(Name = "Date of Birth")]
[DateofBirth(ErrorMessage = "User must be at least 18")]
public DateTime Birthdate { get; set; }
View :
<div class="editor-label">
#Html.LabelFor(m => m.Birthdate)
</div>
<div class="editor-field">
#Html.TextBoxFor(x => x.Birthdate)
#Html.ValidationMessageFor(x => x.Birthdate)
</div>
Top of view before beginform:
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"> </script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MyScripts.js")" type="text/javascript"></script>
<script type="text/javascript">
// we add a custom jquery validation method
jQuery.validator.addMethod('greaterThan', function (value, element, params) {
if (!/Invalid|NaN/.test(new Date(value))) {
return new Date(value) > new Date($(params).val());
}
return isNaN(value) && isNaN($(params).val()) || (parseFloat(value) > parseFloat($(params).val()));
}, '');
// and an unobtrusive adapter
jQuery.validator.unobtrusive.adapters.add('dateofbirth', {}, function (options) {
options.rules['greaterThan'] = true;
options.messages['greaterThan'] = options.message;
});
</script>
That's a dynamic validation which is dependant on current date, and it's not available in default validation options.
You can easily implement it but there is no client side validation generated.
You must implement the client side javascript validation also.
Fore more information about adding a new Validation to ASP.NET MVC check out this ASP .Net MVC 3 unobtrusive custom client validation.
Related
In my .NET Core MVC project, I am trying to validate a user's age is > 18. On the page, the method I've used seems to work. When I enter an date of birth into the field (i.e. 01/01/2016) I receive the validation message "You must be 18 years or older to continue.". When I change the date to (i.e. 01/01/2014) the validation message goes away.
However, when I try to submit the form (with the model as seemingly valid) the focus is changed to the Birthdate field and the client side validation prevents the form from being submitted.
I have a model:
public class Contact
{
[Required]
[StringLength(100)]
[DataType(DataType.Text)]
[Display(Name = "FIRST NAME *")]
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string? FirstName { get; set; }
[Required]
[StringLength(100)]
[DataType(DataType.Text)]
[Display(Name = "LAST NAME *")]
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string? LastName { get; set; }
[Required]
[Display(Name = "BIRTH DATE *")]
[Range(typeof(DateTime), "1/1/1901", "1/1/9999", ErrorMessage = "You must be 18 years or older to continue.")]
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public DateTime? Birthdate { get; set; }
}
and an input:
<div class="form-group">
<label asp-for="Contact!.Birthdate" class="control-label field-label"></label>
<div class="w-embed">
<input asp-for="Contact!.Birthdate" type="date" class="form-control w-input" id="birthdate-inp" data-val-range-max="#DateTime.Now.AddYears(-18).ToString()" />
</div>
<span asp-validation-for="Contact!.Birthdate" class="text-danger"></span>
</div>
and a script:
<script>
$.validator.methods.range = function (value, element, param) {
if ($(element).attr('id') == "birthdate-inp") {
var min = $(element).attr('data-val-range-min');
var max = $(element).attr('data-val-range-max');
var date = new Date(value).getTime();
var minDate = new Date(min).getTime();
var maxDate = new Date(max).getTime();
return this.optional(element) || (date >= minDate && date <= maxDate);
}
return this.optional(element) || (value >= param[0] && value <= param[1]);
};
</script>
and a generated HTML input:
<input type="date" class="form-control w-input valid" id="birthdate-inp" data-val-range-max="1/27/2005 12:45:41 PM" data-val="true" data-val-range="You must be 18 years or older to continue." data-val-range-min="01/01/1901 00:00:00" data-val-required="The BIRTH DATE * field is required." name="Contact.Birthdate" value="" aria-describedby="birthdate-inp-error" aria-invalid="false">
This is the result after pressing the 'Next' button:
I am creating custom attribut for validation to override RegularExpressionAttribute in .Net Core, and Implemented IClientModelValidator for client side validation. validation is apply on field but didn't display Error message for it. ModelState.IsValid is also giving Invalid that field but validation message is not displaying.
ViewModel
[Required]
[Display(Name = "First Name")]
[RestrictSplCharacters]
public string FirstName { get; set; }
Override Attribute
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class RestrictSplCharactersAttribute : RegularExpressionAttribute, IClientModelValidator
{
private string errorMessage= "Special characters or blank space is not allowed in {0}";
public RestrictSplCharactersAttribute()
: base(#"[_A-z0-9]*((-|\s)*[_A-z0-9])*$")
{
this.ErrorMessage = this.errorMessage;
}
public void AddValidation(ClientModelValidationContext context)
{
MergeAttribute(context.Attributes, "data-val", "true");
var errorMessage = FormatErrorMessage(context.ModelMetadata.GetDisplayName());
MergeAttribute(context.Attributes, "data-val-restrictSplCharacters", errorMessage);
}
private bool MergeAttribute(
IDictionary<string, string> attributes,
string key,
string value)
{
if (attributes.ContainsKey(key))
{
return false;
}
attributes.Add(key, value);
return true;
}
}
In Html Control is like
<div class="oneditshow">
<input autocomplete="off" class="k-textbox valid k-valid" data-val="true" data-val-required="The First Name field is required." data-val-restrictSplCharacters="Special characters or blank space is not allowed in First Name" id="FirstName" name="FirstName" placeholder="First Name" required="required" style="width: 100%" value="" aria-required="true" aria-describedby="FirstName-error">
<span class="text-danger field-validation-valid" data-valmsg-for="FirstName" data-valmsg-replace="true" style="display: none;"></span>
</div>
Javascript function
<script>
var $jQval = $.validator;
$jQval.addMethod("restrictSplCharacters",
function (value, element, parameters) {
var regExp = "/[_A-z0-9]*((-|\s)*[_A-z0-9])*$/";
if (value.match(regExp)) {
return true;
} else {
return false;
}
});
var adapters = $jQval.unobtrusive.adapters;
adapters.addBool("restrictSplCharacters");
</script>
Thank you, Client Side validation is not fired because it's kendo UI.
I replace my JavaScript with Below javascript for kendo custom validation Rule.
//register custom validation rules
(function ($, kendo) {
$.extend(true, kendo.ui.validator, {
rules: { // custom rules
restrictSpecialCharacters: function (input, params) {
//check for the rule attribute
if (input.filter("[data-val-restrictSpecialCharacters]").length && input.val()) {
return /[_A-z0-9]*((-|\s)*[_A-z0-9])*$/.test(input.val());
}
return true;
}
},
messages: { //custom rules messages
restrictSpecialCharacters: function (input) {
// return the message text
return input.attr("data-val-restrictSpecialCharacters");
}
}
});
})(jQuery, kendo);
Try with adding following code after public void AddValidation in RestrictSpecialCharactersAttribute.
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
ModelClientValidationRule mvr = new ModelClientValidationRule();
mvr.ErrorMessage = this.eRRORMESSAGE;
mvr.ValidationType = "restrictSpecialCharacters";
return new[] { mvr };
}
You can find more details here.
I want to save the entered value of the database. However, values are sent as null.
I'm glad if I encode additional help.
HomeConteller.cs
[HttpPost]
public void GaleriOlustur(string Adi)
{
GaleriTanim As = new GaleriTanim() { Adi = Adi };
db.GaleriTanims.Add(As);
db.SaveChanges();
islemler islem = new islemler { islemler1 = "Galeri Oluşturuldu", kayitTarihi = DateTime.Now };
db.islemlers.Add(islem);
db.SaveChanges();
RedirectToAction("GaleriYonet", "Home");
}
GaleriYonet.cshtml
#using (Html.BeginForm("GaleriOlustur", "Home",FormMethod.Post,new {Adi="Adi"}))
{
<input type="submit" onclick="GaleriOlustur()" name="Adi" value="Galeri Oluştur"/>
}
GaleriYonet.cshtml "Javascript"
<script type="text/javascript">
function GaleriOlustur() {
var Adi = prompt("Galeri İsmi Giriniz");
if (Adi != null) {
return Adi;
} else {
alert("Bir İsim Girmelisiniz.");
return false;
}
};
Your client side function should either return true or false. Not the value user entered to the prompt.
I also suggest you keep an input variable value (hidden type) in your form with name matching to your action method parameter name. In your javascript method, when user enter a vliad value, you can update this form control value to that.
Also, you need to do return GaleriOlustur() on the onclick event
#using (Html.BeginForm("GaleriOlustur", "Home", FormMethod.Post, new { Adi = "Adi" }))
{
<input type="hidden" name="Adi" />
<input type="submit" onclick="return GaleriOlustur()" value="Galeri Oluştur" />
}
and in js method, set the input field value to the value user entered.
function GaleriOlustur() {
var adi = prompt("Galeri İsmi Giriniz");
if (adi !=="") {
$("input[name='Adi']").val(adi);
return true;
} else {
alert("Bir İsim Girmelisiniz.");
return false;
}
};
<script type="text/javascript">
jQuery.validator.addMethod("mustbetrue", function (value, element, param) {
return element.checked;
});
jQuery.validator.unobtrusive.adapters.addBool("mustbetrue", "required");
that was my script and c# code is ...
public class mustbetrueAttribute : ValidationAttribute, IClientValidatable // IClientValidatable for client side Validation
{
public bool chkbox { get; set; }
public override bool IsValid(object value)
{
if (value is bool)
return (bool)value;
else
return false;
}
// Implement IClientValidatable for client side Validation
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var modelClientValidationRule = new ModelClientValidationRule
{
ValidationType = "mustbetrue",
ErrorMessage = FormatErrorMessage(metadata.DisplayName)
};
modelClientValidationRule.ValidationParameters.Add("mustbetrue", chkbox);
yield return modelClientValidationRule;
//return new ModelClientValidationRule[] { new ModelClientValidationRule { ValidationType = "checkbox", ErrorMessage = this.ErrorMessage } };
//yield return new ModelClientValidationRule
//{
// ErrorMessage = "You must accept Terms and Condition",
// //Given Validation Type will be Used for Client side Validation in Unobtrusive Jquery
// ValidationType = "mustbetrue"
//};
}
}
rendered html:
<li>
<label for="TermsAccepted">Terms and Conditions.</label>
<input data-val="true" data-val-mustbetrue="Please Accept the Terms & Conditions" data-val-mustbetrue-mustbetrue="False" data-val-required="The Terms and Conditions. field is required." id="TermsAccepted" name="TermsAccepted" type="checkbox" value="true" />
<input name="TermsAccepted" type="hidden" value="false" />
</li>
You forget to add:
$.validator.addClassRules("mustbetrue", {
mustbetrue: true
});
Here is a jsfiddle with example
I am attempting to pass data from one view to the other using MVC. I am trying to do a simple guessing game, where on the first view, we enter a range of numbers, then on the second view we try to guess the number. I am able to store the values in my model, but I'm having trouble accessing them/using them in a js script on another view. Sorry if this is too much code, MVC's are hard to ask for help on without showing a full range of code. When I go to the second view to guess the number, it doesn't recognize #ViewBag.(model => model.Low) and it says Load is not defined
Model
pubblic class Range
{
public int High
{
get
{
if (HttpContext.Current.Session["High"] == null)
{
HttpContext.Current.Session["High"] = 3;
}
return (int)HttpContext.Current.Session["High"];
}
set
{
HttpContext.Current.Session["High"] = value;
}
}
public int Low
{
get
{
if (HttpContext.Current.Session["Low"] == null)
{
HttpContext.Current.Session["Low"] = 1;
}
return (int)HttpContext.Current.Session["Low"];
}
set
{
HttpContext.Current.Session["Low"] = value;
}
}
}
Controller
public class GuessingGameController : Controller
{
public ActionResult EnterRange()
{
return View();
}
[HttpPost]
public ActionResult EnterRange(Range range)
{
int high = range.High;
int low = range.Low;
return View(range);
}
public ActionResult GuessNumber()
{
return View();
}
}
View 1: Enter Range
#model GameMVC.Models.Range
#using (Html.BeginForm("EnterRange", "GuessingGame"))
{
<center>
<h2>Lets play a game.</h2>
Enter A Range of Numbers:
<br />
Low: #Html.TextBoxFor(m => m.Low)
<br />
High: #Html.TextBoxFor(m => m.High)
<br />
<input type="submit" value="Enter"/>
<p>
#Html.ActionLink("Now, To the Game", "GuessNumber", "GuessingGame")
</p>
</center>
}
View 2: Guess Number
#model GameMVC.Models.Range
<script language="JavaScript">
var myNum, count;
function Load() {
document.game.status.value = "Please set range of numbers and press the Start button.";
document.game.number.focus();
}
function Round(scale) {
var dd = new Date();
return((Math.round(Math.abs(Math.sin(dd.getTime())) * 8.71 * scale) % scale));
}
function myRange() {
var to = 1 + 1 * #ViewBag.(model => model.Low);
count = 0;
myNum = Round(to);
while (myNum < #ViewBag.(model => model.High);)
myNum = Round(to);
document.game.status.value = "Please guess a number, enter it, and press Guess.";
}
function Guess() {
var numberGuess = document.game.number.value;
count++;
if (numberGuess < myNum) alert("My number is greater than " + numberGuess + ".");
else if (numberGuess > myNum) alert("My number is less than " + numberGuess + ".");
else alert("It takes you " + count + " attempts to guess this number");
}
</script>
<body onload=" Load() ">
<div style="text-align: center;">
<form name=game>
Guess: <input type="text" name="number" size=10>
<p>
<br/>
<input type="button" value="Guess" onclick=" Guess() ">
</p>
#Html.Label("status")
</form>
</div>
</body>
Instead of #ViewBag.(model => model.Low), you could try just using #Model.Low
Model instance is not provided for "GuessAction" view. You need to pass an instance of "Range" to "GuessNumber" view. Since you are accessing values from session, you can simply pass a new instance.
public ActionResult GuessNumber()
{
return View(new Range());
}
Then in javascript you can simply access the data as #Model.High and #Model.Low
You can also use TempData to store the high and low values if you need it only for one request.