4

我的视图模型

Public Class ViewModel
  <SelectOne()>
  Public Property Collection As List(Of Item)
End Class

我的模特

Public Class Item
  <SelectOneProperty(TargetValue:=True, ErrorMessage:="Select at least one.")>
  Public Property Selected As Boolean
  Public Property Value As String
End Class

在我看来,我正在ViewModel.Collection使用编辑器模板进行渲染

@Html.CheckBoxFor(Function(item) item.Selected)
@Html.HiddenFor(Function(item) item.Value)

现在,我想要的是确保使用客户端验证至少选中一个复选框。

我可以通过在属性上设置自定义验证属性Item.Selected并通过注册新适配器来实现这一点$.validator.unobtrusive.adapters.add()

但我觉得属性应该在ViewModel.Collection属性上,因为在服务器端我已经在验证集合的项目之一是否Selected = True使用了这个自定义验证:

<AttributeUsage(AttributeTargets.Field Or AttributeTargets.Property, AllowMultiple:=False, Inherited:=False)>
Public Class SelectOneAttribute
    Inherits ValidationAttribute

    Protected Overrides Function IsValid(value As Object, validationContext As ValidationContext) As ValidationResult

        Dim list As IList

        If value Is Nothing Then
            Return Nothing
        End If

        If TypeOf value Is IEnumerable Then
            list = CType(value, IList)
        Else
            list = New Object() {value}
        End If

        Dim count As Integer = (From item In list
                                From prop In item.GetType().GetProperties()
                                Let attributes = prop.GetCustomAttributes(GetType(RequireOneOrMoreIndicatorAttribute), False)
                                Where attributes.Count > 0
                                From attribute In attributes
                                Where attribute.TargetValue = prop.GetValue(item, Nothing)).Count()
        If count > 0 Then
            Return Nothing
        End If

        Return New ValidationResult(FormatErrorMessage(validationContext.DisplayName))
    End Function
End Class

它使用反射SelectOnePropertyAttribute来查找要检查的属性:

<AttributeUsage(AttributeTargets.Field Or AttributeTargets.Property, AllowMultiple:=False, Inherited:=False)>
Public Class SelectOnePropertyAttribute
    Inherits ValidationAttribute
    Implements IClientValidatable

    Public Property TargetValue As Object

    Public Sub New(targetValue As Object)
        Me.TargetValue = targetValue
    End Sub

    Public Overrides Function IsValid(value As Object) As Boolean
        Return True
    End Function

    Public Function GetClientValidationRules(metadata As System.Web.Mvc.ModelMetadata, context As System.Web.Mvc.ControllerContext) _
        As System.Collections.Generic.IEnumerable(Of System.Web.Mvc.ModelClientValidationRule) _
        Implements System.Web.Mvc.IClientValidatable.GetClientValidationRules

        Dim rule As New ModelClientValidationRule With {
            .ValidationType = "selectone",
            .ErrorMessage = Me.ErrorMessage
        }

        Return New ModelClientValidationRule() {rule}
    End Function
End Class

这就是客户端验证

$.validator.unobtrusive.adapters.add("selectone", function (options) {
    options.rules["selectone"] = {};
    options.messages["selectone"] = options.message;
});

$.validator.addMethod("selectone", function (value, element, parameters) {

    var $el = $(element),
        name = $el.attr("name"),
        field = name.replace(/\[.*$/, "").replace(".", "_"),
        attr = name.replace(/^.*\./, ""),
        test = new RegExp(field + "\\[\\d\\]\." + attr);

    var inputs = $("input[id^=" + field + "]:not([disabled]):not([type=hidden])").filter("input[name$=" + attr + "]");

    for(var i = 0; i < this.errorList.length; i++) {
        var name = $(this.errorList[i].element).attr("name");

        // Do not write out the error more than once.
        if (test.test(name)) return true;
    }

    return inputs.length == 0 || inputs.filter(":checked:not([disabled])").val();
});
4

3 回答 3

0

您正在创建将在侧面运行的自定义验证,但如果您想在客户端运行,则必须为该自定义验证创建 JQuery,然后将其添加到您的页面。

请参考以下链接

http://www.codeproject.com/Articles/275056/Custom-Client-Side-Validation-in-ASP-NET-MVC3

http://www.falconwebtech.com/post/2012/04/21/MVC3-Custom-Client-Side-Validation-with-Unobtrusive-Ajax.aspx

于 2012-09-17T12:10:27.533 回答
0

这是你需要的吗?如果没有选中任何“myCheckbox”,它将阻止表单提交......

$(document).ready(function () {
    $('#submitButtonId').click(function (e) {
        if ($('input[name=myCheckbox]:checked').length == 0) {
            e.preventDefault();
            alert('Please choose at least one checkbox before continuing!');
        }
    });
});
于 2012-09-21T15:24:07.833 回答
0

进行以下更改:-

1.您的视图模型:-

Public Class ViewModel
  <SelectOne()>
  <SelectOneProperty(TargetValue:=True, ErrorMessage:="Select at least one.")>
  Public Property Collection As List(Of Item)
End Class
  1. 我的模型:-

    公共类项目公共属性选择为布尔公共属性值作为字符串结束类

  2. 在您的视图上添加以下行:

    @Html.HiddenFor(x=>x.ItemCollection)

4.然后您将运行视图并查看视图源,然后它将

4.然后您将提交代码,然后它将运行客户端验证。添加调试器并调试它

5.然后修改你的客户端脚本。1.现在您可以从每个复选框中获取值并检查是否选中了您的任何复选框,然后提交表单,否则显示结果。

6.还根据您的要求在 SelectOnePropertyAttribute 中进行更改

7.对于服务器端,我在 c# 上完成了这段代码:-

[AttributeUsage((AttributeTargets.Field | AttributeTargets.Property), AllowMultiple = false, Inherited = false)] 公共类 SelectOneAttribute : ValidationAttribute { public String PropertyName { get; 放; }

    protected override ValidationResult IsValid(object  value, ValidationContext validationContext)
    {
        bool boolVal = false;
        IList list;
        if (value == null)
        {
            return null;
        }
        if (value.GetType().Name == typeof(List<>).Name || value.GetType().Name == typeof(IList<>).Name)
        {
            list = (IList)value;
        }
        else
        {
            list = new object[] {value};
        }
        if (list.Count<0)
            return null;

        if ((from object item in list let propertyInfo = item.GetType().GetProperties() from info in propertyInfo where String.Equals(info.Name, PropertyName) && (bool)info.GetValue(item) == true select item).Any())
        {
            return null;
        }

        return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
    }
}
于 2012-09-18T14:31:45.600 回答