MVC3集合上的客户端验证,至少一个有价值的元素

时间:2012-09-12 12:36:09

标签: .net asp.net-mvc-3 client-side-validation model-validation

我的ViewModel

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();
});

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

  

进行以下更改: -

1.您的ViewModel: -

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 =&GT; x.ItemCollection)

  3. 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));
        }
    }
    

答案 2 :(得分: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!');
        }
    });
});