Is it possible to change when client side validation happens when using MVC data annotations? Currently, all validation seems to occure on keyup, but I need it to occure onchange or losefocus.
ViewModel:
[Display(Name = "First Name")]
[Required(ErrorMessage = "First Name is Required")]
public string FirstName { get; set; }
cshtml
#Html.TextBoxFor(m => m.FirstName, new { placeholder = Html.DisplayNameFor(n => n.FirstName) })
#Html.ValidationMessageFor(m => m.FirstName)
Rendered HTML
<div class="field">
<input data-val="true"
data-val-required="First Name is Required"
id="FirstName"
name="FirstName"
placeholder="First Name"
type="text"
value="">
<span class="field-validation-valid" data-valmsg-for="FirstName" data-valmsg-replace="true"></span>
</div>
This works as it should, but when I type into input, validation occurs as I type. How can I make validation occure after I've clicked or tabbed off the input?
Versions
.NET 4.6.1
Microsoft.Aspnet.Mvc 5.2.3
Microsoft.jQuery.Unobtrusive.Validation 3.2.3
I was able to use Javascript to get the desired behavior.
$.validator.setDefaults({
onkeyup: false
})
All validation now happens on blur
Related
I am trying to validate email field. And I have a regular expression for email
/^[a-z0-9._%+-]+##[a-z0-9.-]+.[a-z]{2,4}$/
In visual studio my code
Email:<br>
<input type="text" ng-model="Email" id="txtEmail" ng-pattern="/^[a-z0-9._%+-]+#[a-z0-9.-]+\.[a-z]{2,4}$/" name="Email" placeholder="Email" required>
<span ng-show="myForm.Email.$error.pattern">Please enter valid Email!</span>
<span ng-show="myForm.Email.$error.required">*</span><br>
An error occuring
Email validation is a popular problem and each regex pattern that you will find doesn't cover all the cases. The best way is to try to send any message to this email or you can use System.Net.Mail.MailAddress class
try
{
var email = new System.Net.Mail.MailAddress(value);
}
catch (FormatException)
{
//handle it here
}
You say you are using C# and MVC. You can use the built in validation; the email validation is supported via an attribute on the field in the model class:
[EmailAddress(ErrorMessage = "The email address is not valid")]
public string Email { get; set; }
The attributes are in the namespace System.ComponentModel.DataAnnotations
The Razor view then needs something like:
<div class="control-group">
#Html.ValidationMessageFor(m => m.Email)
#Html.LabelFor(m => m.Email, new { #class = "editor-label control-label" })
<div class="editor-field controls">
#Html.MbrraceTextBoxFor(m => m.Email, new { #class = "input-xlarge" })
</div>
</div>
There are many variants on the cshtml display styles.
You can create a variable for pattern.
#{
var pattern = "/^[a-z0-9._%+-]+##[a-z0-9.-]+.[a-z]{2,4}$/";
}
<input type="text" ng-model="Email" id="txtEmail" ng-pattern="#pattern" name="Email" placeholder="Email" required>
Can somebody tell me why "This field is required" and "Please insert database name" are being displayed instead of just "Please insert database name"?
This is my model :
public class InstallViewModel
{
[Required(AllowEmptyStrings = false, ErrorMessage = "Please insert database name")]
public string DatabaseName { get; set; }
and this is my view :
<div class="input-group">
<span class="input-group-addon">Database</span>
#Html.TextBoxFor(w => w.DatabaseName, new { #class = "form-control", placeholder = "Database name" })
</div>
#Html.ValidationMessageFor(w=> w.DatabaseName)
Thank you.
EDIT:
Can you see the image attached ? I have some problems uploading images.
The view is a partial view and this is the whole partial view:
#Html.ValidationMessageFor(w => w.DatabaseName)
<div class="input-group">
<span class="input-group-addon">Database</span>
#Html.TextBoxFor(w => w.DatabaseName, new { #class = "form-control", placeholder = "Database name" })
</div>
<br />
#Html.CheckBoxFor(w => w.UseWindowsAuthentication, new { #checked = "checked" }) Use Windows Authentication<br /><br />
<div class="wizard-sqlauth" style="display: none">
<div class="input-group">
<span class="input-group-addon">User name</span>
#Html.TextBoxFor(w => w.UserName, new { #class = "form-control", placeholder = "User name" })
</div>
#Html.ValidationMessageFor(w => w.UserName)<br />
<div class="input-group">
<span class="input-group-addon">Password</span>
#Html.PasswordFor(w => w.Password, new { #class = "form-control" })
</div>
#Html.ValidationMessageFor(w => w.Password)
</div>
DatabaseName is "Required" and your input is empty. (There is only placeholder text)
Are you calling jquery validation "manually" anywhere in javascript, i.e.
$('#myform').valid() ?
That would trigger the default value for the required rule ("This field is required."), and would append it as a label after the input, which is exactly the behavior your are experiencing.
If you really need to use both (MVC's Unobstrusive validation + jQuery validation) you can configure jquery validation to ignore certain fields, for example
$('#myform').validate({
ignore: '#databasefieldId'
});
You have applied the RequiredAttribute attribute to a property to the property DatabaseName which implies that the property must contain a value.
A validation exception is raised if the property is null, an empty string (""), or contains only white-space characters.
You just add #Html.ValidationMessageFor(w=> w.DatabaseName) in the top of div. This will show the summary.
Given this model code
[Required]
[Display(Name = "Name")]
public string Name { get; set; }
the following view code works
#Html.LabelFor(model => model.Name)
#Html.TextBoxFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
Whenever I leave the Name field empty, the TextBox is highlighted in red, and a "The Name field is required." error message appears, which is good.
However, my model also contains an Option[] Options which also need to be validated.
Given this model code
private const string orderNoDisplayName = "Order number";
[Required]
[RegularExpression(#"\d+",
ErrorMessage = "The " + orderNoDisplayName + " field must be numeric.")]
[Display(Name = orderNoDisplayName )]
public string OrderNo { get; set; }
the following view code doesn't quite work as expected
#foreach (var option in Option.GetDefaultOptions())
{
<li>
#Html.TextBoxFor(model => option.OrderNo, new { id = option.IdString })
#Html.ValidationMessageFor(model => option.OrderNo,
null, new { data_valmsg_for = option.IdString })
</li>
}
The very first option works perfectly, but any subsequent option doesn't.
Below is the automatically generated code for 2 options
<ul>
<li> <!-- automatically generated code for 'option_1' -->
<input data-val="true" data-val-regex="The Order number field must be numeric."
data-val-regex-pattern="\d+" data-val-required="The Order number field is required."
id="option_1" name="OrderNo" type="text" value="0" class="input-validation-error">
<span class="field-validation-valid" data-valmsg-for="option_1"
data-valmsg-replace="true"></span>
</li>
<li> <!-- automatically generated code for 'option_2' -->
<input id="option_2" name="OrderNo" type="text" value="0"
class="input-validation-error">
<span class="field-validation-valid" data-valmsg-for="option_2"
data-valmsg-replace="true"></span>
</li>
</ul>
So obviously, MVC did not add any validation attributes to my second option or any subsequent options at all.
Of course, I could hardcode the validations into a handwritten <input> tag, but I'd like to avoid doing so. What can I do to make the validation work for all options, instead of only the first one?
I think the problem is the for loop, as the model binder is not indexing the name field they're coming out identical and it looks like there is only one i.e. name="OrderNo".
Try changing your loop to index it as follows:
#for (var i = 0; i < Option.GetDefaultOptions().Count; i++)
{
<li>
#Html.TextBoxFor(model => Option.GetDefaultOptions()[i].OrderNo, new { id = Option.GetDefaultOptions()[i].IdString })
#Html.ValidationMessageFor(model => Option.GetDefaultOptions()[i].OrderNo,
null, new { data_valmsg_for = Option.GetDefaultOptions()[i].OrderNo.IdString })
</li>
}
You should then see that they're written out as follows:
name="[0].OrderNo"
name="[1].OrderNo"
Where the heck are these things coming from? I like them, and I would like to leverage them elsewhere in my site. It appears they only show when I do regular expression validation in model:
[Display(Name = "Residential")]
[RegularExpression(#"[-+]?[0-9]*\.?[0-9]?[0-9]", ErrorMessage = "Must be a number")]
public Byte? residentialExperience { get; set; }
<div class="editor-label row">
#Html.LabelFor(model => model.residentialExperience)
</div>
<div class="editor-field row">
#Html.EditorFor(model => model.residentialExperience)
#Html.ValidationMessageFor(model => model.residentialExperience)
</div>
How can I use these validation tooltips elsewhere? Also, how can I turn them off?
Also: It's not displaying the same message as I have in my model. It says, "Please enter a number" whereas I have written "Must be a number."
This is because you are outputting a numeric field. If you look at your HTML you will see that you have something like this:
<input type="number" ... />
By defining the type as a numbber, the browser knows what to expect and it will give you a generic message. This is part of Html 5 spec.
If you want to override the default behavior you could do this:
#Html.TextBoxFor(model => model.residentialExperience, new { #type = "text" })
I have below view model
public class QuestionarrieAnswersViewModel
{
public long QuestionID { get; set; }
public string Question { get; set; }
[Required(ErrorMessage="required")]
[StringLength(255, ErrorMessage = "Maximum 255 characters are allowed.")]
public string Answer { get; set; }
}
and i am generating view in below way
#model List<BusinessLayer.Models.ViewModel.QuestionarrieAnswersViewModel>
#using (Ajax.BeginForm("SaveQuestionarrie", "Member", FormMethod.Post, new AjaxOptions { OnBegin = "OnBegin", OnComplete = "OnComplete" }, new { #class = "form-horizontal" }))
{
for(int i=0;i<Model.Count;i++)
{
<div class="control-group">
<div class="head_form">
<label class="control-label">#Model[i].Question</label>
<div class="controls">
#Html.TextAreaFor(m=>m[i].Answer)
#Html.ValidationMessageFor(m => m[i].Answer)
#Html.HiddenFor(m=>m[i].QuestionID)
</div>
</div>
</div>
}
<div class="control-group">
<div class="controls">
<button class="btn" type="submit">Save</button>
</div>
</div>
}
I have set dataannotation on Answer field in above model but its not applying in above view while it works if i generate view in below way
#model BusinessLayer.Models.ViewModel.QuestionarrieAnswersViewModel
#using (Ajax.BeginForm("SaveQuestionarrie", "Member", FormMethod.Post, new AjaxOptions { OnBegin = "OnBegin", OnComplete = "OnComplete" }, new { #class = "form-horizontal" }))
{
#Html.TextAreaFor(m => m.Answer)
#Html.TextAreaFor(m => m.QuestionID)
<div class="control-group">
<div class="controls">
<button class="btn" type="submit">Save</button>
</div>
</div>
}
What's going wrong here...
In order to fire those validation rules, you'll need to use an EditorFor instead of a TextAreaFor.
It's because there's an outstanding issue with validation of TextArea's, see here: http://aspnet.codeplex.com/workitem/8576.
This is due to a bug in the version of jquery.validate.unobtrusive.js that was released with ASP.NET MVC3. This answer is on the same bug, the solution to this is to upgrade to the latest version of jquery.validate.unobtrusive.js - either grab it from an MVC4 project or update using NuGet.
The jquery.validate.unobtrusive.js script doesn't seem to have a version number so if you search in the script for a function called escapeAttributeValue, then this is a version of the script that has this bug fix.
The problem that is addressed in the bug fix is how to handle markup generated having name attributes containing characters that need escaping in a jQuery selector. In this case
<textarea cols="20" name="[0].Answer" rows="2"></textarea>
needs this selector
$('[name=\\[0\\]\\.Answer]')
The client-side DataAnnotation (validation) does not work for the Html.TextAreaFor() helper.
To make it work, you have to decorate the 'Answer' property with the [DataType(DataType.MultilineText)] attribute. And in the view, use Html.EditorFor() helper instead of the Html.TextAreaFor() helper mehthod.
See similar SO answer asp.net mvc TextAreaFor is not getting validated as a required field.