0

I'm trying to implement conditional form validation. On loading, I make all fields with the specified class hidden and depending on the selected type and classes for the block remove the hidden property.

<form>
<div class="mb-3">
    <label for="typeId" class="form-label">Type</label>
    <select id="typeId"
        name="typeId"
        asp-for="typeId"
        asp-items="@Model.TypeListItems"
        class="form-select"
        data-val-required="A Type is required"
        required></select>
    <span class="text-danger validation-message" asp-validation-for="typeId"></span>
</div>
                    
<div class="mb-3 condition-field field1 field2">
    <label for="details" class="form-label">If so, please provide details.</label>
    <textarea rows="3" class="form-control dependsField" name="details" asp-for="details"></textarea>
    <span class="text-danger validation-message" asp-validation-for="details"></span>
</div>

<div class="mb-3 condition-field field1">
    <label for="myfield1" class="form-label">If so, please provide details.</label>
    <textarea rows="3" class="form-control dependsField" name="myfield1" asp-for="myfield1"></textarea>
    <span class="text-danger validation-message" asp-validation-for="myfield1"></span>
</div>

<div class="mb-3 condition-field field2">
    <label for="myfield2" class="form-label">If so, please provide details.</label>
    <textarea rows="3" class="form-control dependsField" name="myfield2" asp-for="myfield2"></textarea>
    <span class="text-danger validation-message" asp-validation-for="myfield2"></span>
</div>
<input type="submit" />
</form>

The JavaScript on document ready:

function onChangeType() {
    hideConditionFields();

    var type = document.getElementById("typeId");
    setupConditionFields(type);
}

function setupConditionFields(type) {
    var css = typeCss[type.value];
    $(".fields").find(css.divClass)
        .each(function (i) {
            $(this).prop("hidden", false);
        });
}

function hideConditionFields() {
    $(".fields").find(".condition-field")
        .each(function (i) {
            $(this).prop("hidden", true);
         });
}

So in the first will be called hideConditionFields() to hide all conditional fields, and then will be shown specified for chosen type fields. If I comment hideConditionFields method's calling - validation works, but my approach doesn't. What do I need to do after hiding and unhiding fields jQuery validation on such fields will continue working?

SlavaHq
  • 23
  • 3
  • Are you using [jQuery Validation plugin](https://jqueryvalidation.org/)? – cheesyMan May 01 '22 at 13:46
  • @cheesyMan I'm not sure, but I think the right answer is I used the jquery Validation plugin with jquery-validation-unobtrusive because the backend is asp.net core. – SlavaHq May 01 '22 at 13:50

2 Answers2

0

If - as I suppose - you're using the jQuery Validation plugin , the hidden inputs are excluded by default from validation (official docs).

You need to configure the plugin to not filter out the hidden input fields:

$('form').validate({
  ignore: [],
  // other validation options/rules, if any
});

Some other useful questions on SO:

  1. jQuery Validate - Enable validation for hidden fields
  2. Ignore all hidden div but not one in jQuery validation
cheesyMan
  • 1,494
  • 1
  • 4
  • 13
0

Refer the following code:

.cshtml: pay attention to the name attribute.

@page
@model Core3Razor.Pages.CustomClientValidateModel

<form method="post" class="fields">
    <div asp-validation-summary="All" class="text-danger"></div>
    <div class="mb-3">
        <label for="typeId" class="form-label">Type</label>
        <select id="typeId"
            name="customModel.typeId"
            asp-for="customModel.typeId"
            asp-items="@Model.TypeListItems"
            class="form-select"
            data-val-required="A Type is required"
            required>
        <option value="">Choose a Type</option>
        </select>
        <span class="text-danger validation-message" asp-validation-for="customModel.typeId"></span>
    </div>
                    
    <div class="mb-3 condition-field field1 field2">
        <label for="details" class="form-label">If so, please provide details (field1 and field2).</label>
        <textarea rows="3" class="form-control dependsField" name="customModel.details" asp-for="customModel.details"></textarea>
        <span class="text-danger validation-message" asp-validation-for="customModel.details"></span>
    </div>

    <div class="mb-3 condition-field field1">
        <label for="myfield1" class="form-label">If so, please provide details (field 1).</label>
        <textarea rows="3" class="form-control dependsField" name="customModel.myfield1" asp-for="customModel.myfield1"></textarea>
        <span class="text-danger validation-message" asp-validation-for="customModel.myfield1"></span>
    </div>

    <div class="mb-3 condition-field field2">
        <label for="myfield2" class="form-label">If so, please provide details (field 2).</label>
        <textarea rows="3" class="form-control dependsField" name="customModel.myfield2" asp-for="customModel.myfield2"></textarea>
        <span class="text-danger validation-message" asp-validation-for="customModel.myfield2"></span>
    </div>
    <input type="submit" />
</form>

@section Scripts {
    @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }

    <script>
    function onChangeType() {
        hideConditionFields();

        var type = document.getElementById("typeId");
        setupConditionFields(type);
    }

    function setupConditionFields(type) {
        var css = type.value;
        $(".fields").find(".condition-field").each(function (index, item) {
            if($(item).hasClass(css)){ 
                $(item).show();
            }
            else{
                 $(item).hide();
            }
         });
    }

    function hideConditionFields() {
        $(".fields").find(".condition-field")
            .each(function (i) {
                $(this).hide();
             });
    }
    $(function(){
        //hide all fields
        hideConditionFields();
        $("#typeId").change(function(){
            onChangeType();
        });
    })
    </script>
}

.cshtml.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace Core3Razor.Pages
{
    public class CustomClientValidateModel : PageModel
    {
        [BindProperties]
        public class CustomModel
        { 
            public int typeId { get; set; }
            [Required] 
            public string details { get; set; }
            [Required] 
            public string myfield1 { get; set; }
            [Required] 
            public string myfield2 { get; set; }
        }
        [BindProperty]
        public CustomModel customModel { get; set; }
        [BindProperty]
        public List<SelectListItem> TypeListItems { get; set; }
        public void OnGet()
        {
            TypeListItems = new List<SelectListItem>()
            {
                new  SelectListItem
                {
                    Value = "field1",
                    Text = "field1"
                },
                new  SelectListItem
                {
                    Value = "field2",
                    Text = "field2"
                } 
            };

        } 
        public IActionResult OnPost()
        {
            //server side validation
            if (!ModelState.IsValid)
            {
                return Page();
            } 
            return RedirectToPage(nameof(Index));
        }
    }
}

Then the output like this:

enter image description here

In the above code, it is using asp-validation-summary="All", if you want to show the validation message based on the model, change it to

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

Zhi Lv
  • 18,845
  • 1
  • 19
  • 30