如何通过 asp.net mvc 中的自定义 jQuery 验证复选框列表

How to validate a list of checkbox through custom jQuery in asp.net mvc

我有一个复选框列表,我想在客户端验证 jQuery 但失败了。我已经在我的项目中添加了 unobtrusive 和 jquery 验证插件。

型号代码为:

 [Required]
 public string name { get; set; }

 [SkillValidation(ErrorMessage = "Select at least 3 skills")]
 public List<CheckBox> skills { get; set; }

其他型号为:

public class CheckBox
{
    //Value of checkbox 
    public int Value { get; set; }
    //description of checkbox 
    public string Text { get; set; }
    //whether the checkbox is selected or not
    public bool IsChecked { get; set; }
}

说明 - SkillValidation() 是我创建的用于执行服务器端验证的自定义属性。

技能验证 class 代码是:

public class SkillValidation : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        List<CheckBox> instance = value as List<CheckBox>;
        int count = instance == null ? 0 : (from p in instance
                                            where p.IsChecked == true
                                            select p).Count();
        if (count >= 3)
            return ValidationResult.Success;
        else
            return new ValidationResult(ErrorMessage);
    }
}

说明:此代码将验证用户在服务器端至少选中 3 个复选框。我没有从 IClientValidatable 接口继承这个 class 因为我知道不可能从 MVC 方式(不显眼的方式)进行验证。

我的查看代码是:

@model demo.MVC.Models.CB
@{
    HtmlHelper.ClientValidationEnabled = true;
    HtmlHelper.UnobtrusiveJavaScriptEnabled = true;
}

@using (Html.BeginForm())
{
    <table>
        <tr>
            <td>
                @Html.LabelFor(model => model.name)
                @Html.EditorFor(model => model.name)
                @Html.ValidationMessageFor(model => model.name)
            </td>
            <td>
                @Html.LabelFor(model => model.skills)
                @Html.CheckBoxFor(m => m.skills[0].IsChecked, new { id = "csharpSkill" }) C#
                @Html.CheckBoxFor(m => m.skills[1].IsChecked, new { id = "aspSkill" }) ASP.NET
                @Html.CheckBoxFor(m => m.skills[2].IsChecked, new { id = "jquerySkill" }) jQuery
                @Html.CheckBoxFor(m => m.skills[3].IsChecked, new { id = "mvcSkill" }) ASP.NET MVC
                @Html.CheckBoxFor(m => m.skills[4].IsChecked, new { id = "razorSkill" }) Razor
                @Html.CheckBoxFor(m => m.skills[5].IsChecked, new { id = "htmlSkill" }) HTML
                @Html.ValidationMessageFor(model => model.skills)
            </td>
        </tr>
        <tr><td colspan="2"><button id="submitButton" type="submit">Submit</button></td></tr>
    </table>
}

@Scripts.Render("~/jQuery")
@Scripts.Render("~/jQueryValidate")
@Scripts.Render("~/Unobtrusive")

说明:在视图中,我为名称创建了文本框,为使用 @Html.CheckBoxFor().

创建的技能创建了 6 个复选框

问题:问题是如果我删除 6 个复选框,那么客户端验证对名称文本框很有效。

如果我放置 6 个复选框并按下按钮,则只有服务器端验证适用于 name 和 checkboxe

我希望客户端验证也适用于 6 个复选框,这样用户至少必须 select 3 个复选框。

我怎样才能实现它?

感谢

您无法使用 MVC 的客户端验证(通过实施 IClientValidatable 和使用 jquery.validation.unobtrusive.js) 来实现这一点。原因是客户端验证规则应用于表单控件,而您没有(并且cannot) 为你的 skills 属性 创建一个表单控件,它是一个集合,而不是一个简单的值类型。

您需要编写自己的脚本来验证选中复选框的数量(如果无效,请使用 @Html.ValidationMessageFor(model => model.skills)

生成的占位符

为了模仿 jquery 的 'lazy' 验证,首先处理 .submit() 事件,然后处理复选框的 .click() 事件。

修改您的第二个 <td> 元素以添加一个 id 属性来选择复选框(另请参阅下面的注释)

<td id="skills">
    .... // your checkboxes

并添加以下脚本

var validateSkillsOnCheck = false; // for lazy validation
var requiredSkills = 3;
var skills = $('#skills input[type="checkbox"]');
var errorMessage = 'Select at least 3 skills';
var errorElement = $('span[data-valmsg-for="skills"]');

// function to validate the required number of skills
function validateSkills() {
    var selectedSkills = skills.filter(':checked').length;
    var isValid = selectedSkills > requiredSkills;
    if (!isValid) {
        errorElement.addClass('field-validation-error').removeClass('field-validation-valid').text(errorMessage);
    } else {
        errorElement.addClass('field-validation-valid').removeClass('field-validation-error').text('');
    }
    return (isValid);
}

$('form').submit(function () {
    validateSkillsOnCheck = true;
    if (!validateSkills()) {
        return false; // prevent submit
    }
});
$('#skills').on('click', 'input', function () {
    if (validateSkillsOnCheck) {
        validateSkills();
    }
})

一些旁注。

  1. 表格用于表格数据,而不是布局并使用 <table> element 不适合你的情况。
  2. 你的@Html.LabelFor(model => model.skills)不合适(你 skills 没有表单控件,因此点击它不会 将焦点放在任何东西上)。那应该只是一个 <span>@Html.DisplayNameFor(m =>m.skills)</span> 或类似的元素。
  3. 但是您应该为每个复选框创建标签。您的模型有 3 个属性,包括 TextValue 并且不清楚它们之间的区别,无论如何,您永远不会将它们包含在视图中。我假设您至少要提交 Value 属性 以便您知道选择了哪些技能

    <label>
        @Html.CheckBoxFor(m =>m.skills[i].IsChecked)
        <span>@Model.skills[i].Text</span>
    </label>
    @Html.HiddenFor(m =>m.skills[i].Value)