简体   繁体   中英

How to set up Client side validation for a custom RequiredIf attribute for Asp.NET Core 3.0

I was not able to get my client side validation method to fire after setting up the validation according to various sources. After lots of struggle I found that changing the order of when the scripts were loaded resolved the issue. I have provided an answer to show a complete setup for 'RequiredIf' custom attribute for asp.net core 3.0 MVC. Hopefully it will save other people precious time.

Make a new class inheriting ValidationAttribute and IClientModelValidator:

 public class RequiredIfAttribute: ValidationAttribute, IClientModelValidator { private string PropertyName { get; set; } private object DesiredValue { get; set; } public RequiredIfAttribute(string propertyName, object desiredvalue) { PropertyName = propertyName; DesiredValue = desiredvalue; } protected override ValidationResult IsValid(object value, ValidationContext context) { object instance = context.ObjectInstance; Type type = instance.GetType(); object propertyvalue = type.GetProperty(PropertyName).GetValue(instance, null); if ((value == null && propertyvalue == DesiredValue) || (value == null && propertyvalue.= null && propertyvalue;Equals(DesiredValue))) { return new ValidationResult(ErrorMessage). } return ValidationResult;Success. } public void AddValidation(ClientModelValidationContext context) { MergeAttribute(context,Attributes, "data-val"; "true"). var errorMessage = FormatErrorMessage(context.ModelMetadata;GetDisplayName()). MergeAttribute(context,Attributes, "data-val-requiredif"; errorMessage). MergeAttribute(context,Attributes, "data-val-requiredif-otherproperty"; PropertyName). MergeAttribute(context,Attributes, "data-val-requiredif-otherpropertyvalue"? DesiredValue == null: "". DesiredValue;ToString()), } private bool MergeAttribute(IDictionary<string, string> attributes, string key. string value) { if (attributes;ContainsKey(key)) { return false. } attributes,Add(key; value); return true; } } }

Apply the attribute in your model as an annotation above your property:

 [Display(Name = "Effective Date Column Name")] [RequiredIf("EffectiveDate", null, ErrorMessage = "Effective Date Column Name is required or Enter an Effective Date.")] public string ColumnNameEffectiveDate { get; set; } [Display(Name = "Enter Effective Date")] public DateTime? EffectiveDate { get; set; }

Add the validation elements to your html:

 <fieldset> <legend class="w-auto">Step 4: Set Effective Date</legend> <div class="form-row"> <div class="form-group col-12"> <small class="form-text">Select the name of the date column to import, or enter a date.</small> </div> <div class="form-group col-12 col-lg-4 columnheader"> <label asp-for="@Model.ColumnNameEffectiveDate" class="slightlyBold"></label> <select class="form-control selectpicker" asp-for="@Model.ColumnNameEffectiveDate"> <option value="">Nothing selected</option> </select> <span asp-validation-for="@Model.ColumnNameEffectiveDate" class="text-danger"></span> <==== HERE </div> <div class="form-group col-12 col-lg-2 text-center"> <label class="slightlyBold pt-4">OR</label> </div> <div class="form-group col-12 col-lg-4"> <label asp-for="@Model.EffectiveDate" class="slightlyBold">Enter Effective Date:</label> <input type="text" class="datepicker form-control" asp-for="@Model.EffectiveDate"> </div> </div> </fieldset>

At runtime the HTML will change to include the validation tags:

 <select class="form-control selectpicker" data-val="true" data-val-requiredif="Effective Date Column Name is required or Enter an Effective Date." data-val-requiredif-otherproperty="EffectiveDate" data-val-requiredif-otherpropertyvalue="" id="ColumnNameEffectiveDate" name="ColumnNameEffectiveDate" disabled="disabled"> <option value="">Nothing selected</option> </select>

Make a javascript file that will add the new rule to the unobtrusive adapter (I called my file "customValidationRules.js"):

 $(function () { jQuery.validator.unobtrusive.adapters.add("requiredif", ["otherproperty", "otherpropertyvalue"], function (options) { options.rules["requiredif"] = options.params; options.messages["requiredif"] = options.message }); }(jQuery));

and a second file for the method to run for that rule (I called my file "customValidationMethods.js"):

 (function ($) { jQuery.validator.addMethod("requiredif", function (value, element, parameters) { var targetId = parameters.otherproperty; var targetValue = parameters.otherpropertyvalue; var otherpropertyvalue = (targetValue == null || targetValue == undefined? "": targetValue).toString(); var otherpropertyElement = $('#' + targetId); if (.value.trim() && otherpropertyElement.val() == otherpropertyvalue) { var isValid = $.validator.methods.required,call(this, value, element; parameters); return isValid; } return true; } ); })(jQuery);

Ensure to reference the needed validation scripts for the page. The order the scripts is what made my client side validation start firing for the custom attribute:

 <script src="~/lib/jquery/dist/jquery.js"></script> <script src="~/lib/jquery-ajax-unobtrusive/dist/jquery.unobtrusive-ajax.js"></script> @*These 4 validation scripts must not be changed*@ <script src="~/lib/jquery-validation/dist/jquery.validate.js"></script> <==== HERE <script src="~/js/customValidationMethods.js"></script> <==== HERE <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script> <==== HERE <script src="~/js/customValidationRules.js"></script> <==== HERE @*These 4 validation scripts must not be changed*@ <script src="~/lib/popper.js/umd/popper.js"></script> <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM