私のビューモデル
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)
ここで、クライアント側の検証を使用して、少なくとも 1 つのチェックボックスがオンになっていることを確認します。
プロパティにカスタム検証属性を設定しItem.Selected
、新しいアダプターを登録することでこれを実現できます$.validator.unobtrusive.adapters.add()
しかし、コレクションのアイテムの1つがこのカスタム検証を使用して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();
});