我的视图模型
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();
});