Client-Side Validation in Custom Validation Attribute - ASP.NET MVC 4

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

  1. Implement IClientValidatable in your attribute.

    public class FirstNameValidator : ValidationAttribute, IClientValidatable

  2. Write javascript adapter and include it in your view.

  3. 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



Leave a reply



Submit