3

好的,所以我有這些產品的複選框,我想確保至少選擇一個產品。多個複選框的自定義DataAnnotation

要做到這一點,我的視圖模型包含:

[DisplayName(@"Product Line")] 
[MinChecked(1)] 
public List<CheckboxInfo> ActiveProducts { get; set; } 

的視圖只包含:

@Html.EditorFor(x => x.ActiveProducts) 

這EditorTemplate包含:

@model Rad.Models.CheckboxInfo 

@Html.HiddenFor(x => x.Value) 
@Html.HiddenFor(x => x.Name) 
@Html.CheckBoxFor(x => x.Selected) 
@Html.LabelFor(x => x.Selected, Model.Name) 

定製dataannotation是:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] 
public class MinCheckedAttribute : ValidationAttribute, IClientValidatable 
{ 
    public int MinValue { get; set; } 

    public MinCheckedAttribute(int minValue) 
    { 
     MinValue = minValue; 
     ErrorMessage = "At least " + MinValue + " {0} needs to be checked."; 
    } 

    public override string FormatErrorMessage(string propName) 
    { 
     return string.Format(ErrorMessage, propName); 
    } 

    protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     try 
     { 
      List<CheckboxInfo> valueList = (List<CheckboxInfo>)value; 
      foreach (var valueItem in valueList) 
      { 
       if (valueItem.Selected) 
       { 
        return ValidationResult.Success; 
       } 
      } 
      return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); 
     } 
     catch (Exception x) 
     { 
      return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); 
     } 
    } 

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
    { 
     var rule = new ModelClientValidationRule 
     { 
      ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()), 
      ValidationType = "minchecked", 
     }; 

     rule.ValidationParameters["minvalue"] = MinValue; 

     yield return rule; 
    } 
} 

jQuery的部分是:

$.validator.addMethod('minchecked', function (value, element, params) { 
    var minValue = params['minvalue']; 
    alert(minValue); 
    $(element).each(function() { 
     if ($(this).is(':checked')) { 
      return true; 
     } 
    }); 
    return false; 
}); 
$.validator.unobtrusive.adapters.add('minchecked', ['minvalue'], function (options) { 
    options.messages['minchecked'] = options.message; 
    options.rules['minchecked'] = options.params; 
}); 

所以,驗證工作的服務器端。

但是,如何讓不顯眼的驗證工作?由於某些原因,

GetClientValidationRules沒有將HTML5附加到複選框。

+0

斷點是否會碰到GetClientValidationRules? – frictionlesspulley

+0

不,不。這就是我問的問題,是如何讓它重視。 – ScubaSteve

回答

1

我有一個非常類似於上面的實現和這個客戶端jQuery代碼確實工作(附加到HTML5)的一組複選框,是模型的一部分。它將從數據註釋中傳輸ErrorMessage。

[Display(Name = "Location1")] 
    [CheckAtLeastOne(ErrorMessage = "Must check at least one Location")] 
    public DateTime Location1 { get; set; } 

    [Display(Name = "Location2")] 
    public DateTime Location2 { get; set; } 

    [Display(Name = "Location3")] 
    public DateTime Location3 { get; set; } 

    [Display(Name = "Location4")] 
    public DateTime Location4 { get; set; } 

    $(function() { 
    $.validator.addMethod("checkatleastone", function (value, element) { 
     var tag = $("#editform-locations").find(":checkbox"); 
     return tag.filter(':checked').length; 
    }); 
}); 
$.validator.unobtrusive.adapters.addBool("checkatleastone"); 

但是,在我的情況下,我有另一個複選框的集合,不是模型的一部分。它是一個單獨的表格,所以它被填充到Viewbag中,該Viewbag用於生成複選框列表。服務器端將無法工作,但客戶端驗證通過使用此jquery並將匹配的類名稱添加到複選框的html工作。

$(function() { 
    $.validator.addMethod("CheckOneCategory", function (value, element) { 
     var tag = $("#editform-categories").find(":checkbox"); 
     return tag.filter(':checked').length; 
    }, "Select at least one Product/Service Category"); 
    $.validator.addClassRules("require-one-category", { CheckOneCategory: true }); 
});