Search code examples
javascriptjqueryasp.net-corejquery-validateunobtrusive-validation

Custom errorClass in Unobtrusive Validation ignored with Server Side Validation


I am using unobtrusive validation in asp.net core and have set a custom class in order to utilise the bootstrap CSS classes.

This works nicely for client side validation, but the custom class is ignored with server side validation and reverts to the default "input-validation-error" instead of "is-invalid".

How do I get the custom error class to work with server side validation?

const validationCustomSettings = {
        validClass: "is-valid",
        errorClass: "is-invalid"
};
// Need to set validation settings on both the validator and unobtrusive options.
jQuery.validator.setDefaults(validationCustomSettings);    
jQuery.validator.unobtrusive.options = validationCustomSettings;

Razor Code:

ModelState.AddModelError("ADR.TTIS",
                        "Test server side model error.");

Razor Page:

<form id="myForm" method="post">
    <div class="row">
        <div class="col-sm-3">
            <label asp-for="ADR.AircraftID" class="form-label"></label>
            <select asp-for="ADR.AircraftID" asp-items="@(new SelectList(Model.Aircraft,"AircraftID","Registration"))" class="form-select" required>
                <option></option>
            </select>
            <span asp-validation-for="ADR.AircraftID" class="text-danger"></span>
        </div>
        <div class="col-sm-3">
            <label asp-for="ADR.PersonID" class="form-label"></label>
            <select asp-for="ADR.PersonID" asp-items="@(new SelectList(Model.Person,"PersonID","FullName"))" class="form-select" required>
                <option></option>
            </select>
            <span asp-validation-for="ADR.PersonID" class="text-danger"></span>
        </div>
        <div class="col-sm-3">
            <label asp-for="ADR.Date" class="form-label"></label>
            <kendo-datepicker for="ADR.Date" class="form-control" required></kendo-datepicker>
            <span asp-validation-for="ADR.Date" class="text-danger"></span>
        </div>
        <div class="col-sm-3">
            <label asp-for="ADR.TTIS" class="form-label"></label>
            <input asp-for="ADR.TTIS" class="form-control" required />
            <span asp-validation-for="ADR.TTIS" class="text-danger"></span>
        </div>
        <div class="col-sm-12">
            <label asp-for="ADR.Details" class="form-label"></label>
            <textarea asp-for="ADR.Details" class="form-control" rows="3" required></textarea>
            <span asp-validation-for="ADR.Details" class="text-danger"></span>
        </div>
    </div>
    <br />
    <div class="form-check">
        <input asp-for="ADR.Deferred" class="form-check-input isdeferred" type="checkbox" />
        <label asp-for="ADR.Deferred" class="form-check-label"></label>
        <span asp-validation-for="ADR.Deferred" class="text-danger"></span>
    </div>
    <div class="row">
        <div class="col-sm-6">
            <label asp-for="ADR.MELRef" class="form-label"></label>
            <input asp-for="ADR.MELRef" class="form-control deferred" />
            <span asp-validation-for="ADR.MELRef" class="text-danger"></span>
        </div>
        <div class="col-sm-2">
            <label asp-for="ADR.DeferralExpiry" class="form-label"></label>
            <kendo-datepicker for="ADR.DeferralExpiry" class="form-control deferred"></kendo-datepicker>
            <span asp-validation-for="ADR.DeferralExpiry" class="text-danger"></span>
        </div>
    </div>

    <div class="d-grid gap-2 d-md-flex justify-content-md-end">
        <a class="btn btn-outline-secondary" asp-page="./Index"> Close</a>
        <input type="submit" id="Submit" value="Submit" class="btn btn-primary" />
    </div>
</form>

Solution

  • The class attribute has no relationship with jquery validate now( you could try to remove the related js files,it would still be input-validation-error ) ,It was generated by TagHelper

    You need a TagHelper like:

    [HtmlTargetElement("input", Attributes = ValidateFor + "," + ValidClass)]
        public class ValidationErrorClassTagHelper : TagHelper
        {
            private const string ValidateFor = "validate-for";
    
            private const string ValidClass = "invalid-class";
    
            [HtmlAttributeName(ValidateFor)]
            public ModelExpression For { get; set; } 
    
            [HtmlAttributeName(ValidClass)]
            public string ValidateErrorClass { get; set; } = "";
    
            [HtmlAttributeNotBound]
            [ViewContext]
            public ViewContext ViewContext { get; set; } 
    
            public override void Process(TagHelperContext context, TagHelperOutput output)
            {
                ViewContext.ViewData.ModelState.TryGetValue(For.Name, out ModelStateEntry entry);
                if (entry != null && entry.Errors.Any())
                {
                    output.Attributes.SetAttribute("class", "form-control "+ ValidateErrorClass); 
                }
            }
        }
    

    Regist the taghelper in _viewimports.cshtml

    in View,add attributes to your input element:

    <input validate-for="Name" invalid-class="is-invalid" asp-for="Name" class="form-control" />
    

    on myside,it works:

    enter image description here