0

I want to make conditional validation in ASP.NET MVC Core 3.1. I have written custom validation and it works fine in server-side validation but I am unable to perform client-side validation. In my sample application, there is a Salary textbox, which is only required if the Role=Teacher is selected in the Roles dropdown. Could you please help me in the client-side validation part and here is the complete sample code.

Employee model class

public class Employee
    {
        public int Id { get; set; }

        [Required(ErrorMessage = "Please enter name")]
        public string Name { get; set; }

        [Required(ErrorMessage = "Please enter email")]
        [EmailAddress]
        public string Email { get; set; }

        [Required(ErrorMessage = "Please enter  role")]
        [EnumDataType(typeof(Roles))]
        public Roles? Role { get; set; }

        [Required(ErrorMessage = "Please Enter Hire Date")]
        [Display(Name = "Hire Date")]
        public DateTime? HireDate { get; set; }

        [RequiredIf("Role", Roles.Teacher, ErrorMessage = "Please enter salary")]
        public int? Salary { get; set; }
    }

Roles enum

 public enum Roles
    {
        Student = 1,
        Teacher = 2,
        Assistant = 3        
    }

RequiredIfAttribute custom validation class

public class RequiredIfAttribute : ValidationAttribute, IClientModelValidator
    {
        public string PropertyName { get; set; }
        public object Value { get; set; }

        public RequiredIfAttribute(string propertyName, object value, string errorMessage = "")
        {
            PropertyName = propertyName;
            ErrorMessage = errorMessage;
            Value = value;
        }

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var instance = validationContext.ObjectInstance;
            var type = instance.GetType();
            var proprtyvalue = type.GetProperty(PropertyName).GetValue(instance, null);
            if (proprtyvalue != null)
            {
                if (proprtyvalue.ToString() == Value.ToString() && value == null)
                {
                    return new ValidationResult(ErrorMessage);
                }
            }     
            return ValidationResult.Success;
        }

        public void AddValidation(ClientModelValidationContext context)
        {
            context.Attributes.Add("data-val", "true");
            context.Attributes.Add("data-val-country", ErrorMessage);
        }
    }

Index view for the UI

@model ASPNETCoreValidations.Models.Employee
@using ASPNETCoreValidations.Models.enums
@{
    ViewBag.Title = "Index";
}

<h1>Create</h1>

<h4>Business unit</h4>
<hr />
<div class="container">
    <form asp-action="Index">

        <div asp-validation-summary="All" class="text-danger"></div>

        <div class="form-group">
            <div class="row">
                <div class="col-md-6">
                    <label asp-for="Name" class="control-label"></label>
                    <input asp-for="Name" class="form-control" />
                    <span asp-validation-for="Name" class="text-danger"></span>
                </div>
                <div class="col-md-6">
                    <label asp-for="Email" class="control-label"></label>
                    <input asp-for="Email" class="form-control" />
                    <span asp-validation-for="Email" class="text-danger"></span>
                </div>
            </div>
        </div>


        <div class="form-group">
            <div class="row">
                <div class="col-md-6">
                    <label asp-for="Role" class="control-label"></label>
                    <select asp-for="Role" class="form-control" asp-items="Html.GetEnumSelectList<Roles>()">
                        <option value="">Select Department</option>
                    </select>
                    <span asp-validation-for="Role" class="text-danger"></span>
                </div>
                <div class="col-md-6">
                    <label asp-for="HireDate" class="control-label"></label>
                    <input asp-for="HireDate" class="form-control" />
                    <span asp-validation-for="HireDate" class="text-danger"></span>
                </div>
            </div>
        </div>

        <div class="form-group">
            <div class="row">
                <div class="col-md-6">
                    <label asp-for="Salary" class="control-label"></label>
                    <input asp-for="Salary" class="form-control" />
                    <span asp-validation-for="Salary" class="text-danger"></span>
                </div>
            </div>
        </div>

        <div class="form-group">
            <input type="submit" value="Create" class="btn btn-primary" />
        </div>
    </form>
</div>


@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
    <script src="~/js/RequiredIfValidate.js"></script>
}

Jquery for client-side validation

jQuery.validator.addMethod("requiredif",
    function (value, element, param) {    
        
      // I need help here. This method never gets executed and I don't know how to implement validation here ...
      // return true or false depending on the condition
    });

jQuery.validator.unobtrusive.adapters.addBool("requiredif");

Index action

        [HttpPost]
        [ValidateAntiForgeryToken]
        public IActionResult Index(Employee employee)
        {
            if (ModelState.IsValid)
            {
                RedirectToAction("Index");
            }

            return View();
        }

1 Answer 1

1

According to your description, I suggest you could add a property in the RequiredIfAttribute AddValidation attribute to add the role to the input salary.

Then I suggest you could try to use below validation unobtrusive scripts:

RequiredIfAttribute :

public class RequiredIfAttribute : ValidationAttribute, IClientModelValidator
{
    public string PropertyName { get; set; }
    public object Value { get; set; }

    public RequiredIfAttribute(string propertyName, object value, string errorMessage = "")
    {
        PropertyName = propertyName;
        ErrorMessage = errorMessage;
        Value = value;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var instance = validationContext.ObjectInstance;
        var type = instance.GetType();
        var proprtyvalue = type.GetProperty(PropertyName).GetValue(instance, null);
        if (proprtyvalue != null)
        {
            if (proprtyvalue.ToString() == Value.ToString() && value == null)
            {
                return new ValidationResult(ErrorMessage);
            }
        }
        return ValidationResult.Success;
    }

    public void AddValidation(ClientModelValidationContext context)
    {
        context.Attributes.Add("data-val", "true");
        context.Attributes.Add("data-val-country", ErrorMessage);
        context.Attributes.Add("data-val-country-role", Value.ToString());
    }
}

Scripts:

@section Scripts{
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.1/jquery.validate.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"></script>

    <script>

        $.validator.addMethod('country', function (value, element, params) {
            var genre = $(params[0]).val(), role = params[1], salar = value;

            var selecttest = $("#Role option:selected").text();
 
            if (selecttest == role) {
                if (value.length == 0) {
                    console.log("selecttest == role value = null");
                    return false;

                } else {
                    console.log("selecttest == role value != null");
                    return true;
                }
            } else {
                console.log("selecttest != role");
                return true;
            }



        });

        $.validator.unobtrusive.adapters.add('country', ['role'], function (options) {
            var element = $(options.form).find('select#Salary')[0];

            options.rules['country'] = [element, options.params['role']];
            options.messages['country'] = options.message;
        });
    </script>

}

Result:

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

your implementation in client side is not complete. You hardcoded the dependent element in validation. So, your approach only works if the dependent element calls #Role

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.