client-side validation in custom validation attribute - asp.net mvc 4
Take a look at this: http://thewayofcode.wordpress.com/tag/custom-unobtrusive-validation/
Using this tutorial I got my custom validation code running with no problem. The only difference I can spot in your code is the way you created the $.validator.unobtrusive.adapters.add
function. The parameters are a little bit different but, maybe, the problem is just that you have not defined the rule
part of your adapter.
Try using something like this:
$.validator.unobtrusive.adapters.add("requiredif", ["requiredif"], function (options) {
options.rules["requiredif"] = "#" + options.params.requiredif;
options.messages["requiredif"] = options.message;
});
or this
$.validator.unobtrusive.adapters.add("requiredif", function (options) {
options.rules["requiredif"] = "#" + options.element.name.replace('.', '_'); // mvc html helpers
options.messages["requiredif"] = options.message;
});
About the rule
(taken from the link):
The jQuery rules array for this HTML element. The adapter is expected
to add item(s) to this rules array for the specific jQuery Validate
validators that it wants to attach. The name is the name of the jQuery
Validate rule, and the value is the parameter values for the jQuery
Validate rule.
ASP.NET Core client side validation for custom validation attribute on razor page
How can I get the custom validation attribute to work the same way?
If you'd like to do same validation logic on client side as you did on custom server-side validation attribute on model property.
You can try to implement custom client-side validation based on your actual requirement, for more information, please refer to this doc:
https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-3.1#custom-client-side-validation
Besides, if possible, you can try to use the [Remote] attribute that also enables us to validate combinations of fields, which might help you achieve same requirement easily.
ASP.Net Core MVC - Client-side validation for custom attribute
The IClientModelValidator
is in fact the right interface. I've made a contrived sample implementation below.
Attribute
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public sealed class CannotBeRedAttribute : ValidationAttribute, IClientModelValidator
{
public override bool IsValid(object value)
{
var message = value as string;
return message?.ToUpper() == "RED";
}
public void AddValidation(ClientModelValidationContext context)
{
MergeAttribute(context.Attributes, "data-val", "true");
var errorMessage = FormatErrorMessage(context.ModelMetadata.GetDisplayName());
MergeAttribute(context.Attributes, "data-val-cannotbered", errorMessage);
}
private bool MergeAttribute(
IDictionary<string, string> attributes,
string key,
string value)
{
if (attributes.ContainsKey(key))
{
return false;
}
attributes.Add(key, value);
return true;
}
}
Model
public class ContactModel
{
[CannotBeRed(ErrorMessage = "Red is not allowed!")]
public string Message { get; set; }
}
View
@model WebApplication.Models.ContactModel
<form asp-action="Contact" method="post">
<label asp-for="Message"></label>
<input asp-for="Message" />
<span asp-validation-for="Message"></span>
<input type="submit" value="Save" />
</form>
@section scripts {
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
<script>
$.validator.addMethod("cannotbered",
function (value, element, parameters) {
return value.toUpperCase() !== "RED";
});
$.validator.unobtrusive.adapters.add("cannotbered", [], function (options) {
options.rules.cannotbered = {};
options.messages["cannotbered"] = options.message;
});
</script>
}
MVC Custom Validation for List on Client Side
The reason you will not get client side validation is because the html helpers generate data-val-*
attributes for controls associated with properties. jquery.validate.unobtrusive
reads those attributes when the form is parsed and using rules, displays an error message in the appropriate element generated by ValidationMessageFor()
associated with that control (it does this by matching up the id
attributes of the elements - the error message is generated in a span with <span for="TheIdOfTheAssociatedControl" ...>
).
You don't (and cant) generate a control for property DeclarationQuestions
(only for properties of each item in DeclarationQuestions
so there is nothing that can be matched up.
You could handle this by including your own error message placeholder and intercepting the .submit
event
html (add css to style #conditions-error
as display:none;
)
<span id="delarations-error" class="field-validation-error">
<span>You must accept all declarations to continue.</span>
</span>
Script
var declarationsError = $('#delarations-error');
$('form').submit(function() {
var isValid = $('.yourCheckBoxClass').not(':checked') == 0;
if(!isValid) {
declarationsError.show(); // display error message
return false; // prevent submit
}
});
$('.yourCheckBoxClass').change(function() {
if($(this).is(':checked')) {
declarationsError.hide(); // hide error message
}
});
Side note: You loop for generating the checkboxes should be
for (int i = 0; i < Model.DeclarationQuestions.Count; i++)
{
@Html.CheckBoxFor(m => m.DeclarationQuestions[i].Answer, new { id = "DeclarationQuestions" + i})
}
custom validator MVC + validation client side
Implement IClientValidatable in your attribute.
public class FirstNameValidator : ValidationAttribute, IClientValidatable
Write javascript adapter and include it in your view.
Write javascript validation rule itself and include it in your view.
You can search "asp.net mvc 4 custom client side validation" for more details.
For example, you can look Custom data annotation validator or How to support client side custom validation
Client side validation for custom attribute
I'm not sure what you mean by "not working" but your jquery validation function appears to be oddly formed. I assume you want it to return false (aka invalid) if the value contains company.com anywhere. If so, your method should be something like:
$.validator.addMethod("noncompanyemail", function (value, element, params) {
return (value.toLowerCase().indexOf('company.com') == -1);
});
MVC Custom Validation String Array Client Side
You get "System.String[]"
string because the value of ValidationParameters["propertynames"]
is written by calling ToString
on it, so string[]
variable returns "System.String[]"
in this case. If you need to output specific value you need to format it by yourself in your validation attribute. For example, change
rule.ValidationParameters["propertynames"] = PropertyNames;
to
rule.ValidationParameters["propertynames"] = string.Join(",", PropertyNames);
and you will get
data-val-total-propertynames="SomeOtherField1,SomeOtherField2"
Client side validation for custom annotation Asp.Net MVC 4
That article is specific to MVC 2 which used MicrosoftAjax. MVC 4 no longer includes the MS Ajax files as they have been deprecated and the preferred method is to use jquery.
To verify your settings, make sure these scripts are in your layout
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
<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/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
And these two settings are present in the appSettings section in your web.config file
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
So when you add data annotations to your ViewModels you get client side and server side validation both
public class MyModel
{
[Required]
[StringLength(30)]
public string FirstName { get; set; }
[Required]
[StringLength(30)]
public string LastName { get; set; }
}
In your view just make sure you have code like this
<div>
@Html.LabelFor(model => model.FirstName)
</div>
<div>
@Html.TextBoxFor(model => model.FirstName) <br/>
@Html.ValidationMessageFor(model => model.FirstName)
</div>
<div>
@Html.LabelFor(model => model.LastName)
</div>
<div>
@Html.TextBoxFor(model => model.LastName) <br/>
@Html.ValidationMessageFor(model => model.LastName)
</div>
Update
Here's an example of a custom validator that I have called RateRequiredIfCustomIndexRate
This is the javascript side of it so that it gets added to jquery validation
$("document").ready(function () {
var isCustomRateRequired = document.getElementById("IsCustomRateRequired");
isCustomRateRequired.onchange = function () {
if (this.checked) {
$('#Rate').attr('disabled', 'disabled');
$('#Rate').val('');
}
else {
$('#Rate').removeAttr('disabled');
}
};
});
jQuery.validator.addMethod("raterequiredifcustomindexrate", function (value, element, param) {
var rateRequired = $("#CustomRateRequired").val();
if (rateRequired && value == "") {
return false;
}
return true;
});
jQuery.validator.unobtrusive.adapters.addBool("raterequiredifcustomindexrate");
Related Topics
Is a Reference Assignment Threadsafe
Can Someone Explain How Bcrypt Verifies a Hash
Automatically Rename a File If It Already Exists in Windows Way
Writing to Then Reading from a Memorystream
C# Image.Clone Out of Memory Exception
Client-Side Validation in Custom Validation Attribute - ASP.NET MVC 4
How to Convert String "07:35" (Hh:Mm) to Timespan
Getting Variable by Name in C#
How to Create Trial Version of .Net Software
How to Put Text on Progressbar
How to Get the Local Network Ip Address of a Computer Programmatically
C# Automatic Property Deserialization of JSON