2012-02-29 97 views
0

我正在使用自定義屬性在冗長的表單上進行驗證。其中一個傳入字段是一系列複選框,我使用它來允許用戶爲相應的數據庫字段設置多個值(我知道我可以使用MultiSelectList,但我不是他們的忠實粉絲)。然後,我將ActionResult的POST方法中的各種複選框值組裝成一個字符串,然後將其加載到數據庫中。這部分運作良好。MVC 3多個複選框的自定義驗證屬性

但是,我需要驗證他們檢查了至少一個複選框(即數據庫值本身不能爲空)。所以我寫了一個自定義驗證屬性,查找每個複選框的存在,並且如果至少存在一個複選框,那麼它將通過驗證。這是我寫的驗證本身的代碼:

public class ConfirmLAAttribute : ValidationAttribute 
{ 
    public ConfirmLAAttribute() 
    { 
    } 

    protected override ValidationResult IsValid(Object value, ValidationContext validationContext) 
    { 
     string lAppTest = String.Empty; 
     lAppTest += (validationContext.ObjectType.GetProperty("LAAccent") != null) ? "X" : String.Empty; 
     lAppTest += (validationContext.ObjectType.GetProperty("LAShade") != null) ? "X" : String.Empty; 
     lAppTest += (validationContext.ObjectType.GetProperty("LAArticulation") != null) ? "X" : String.Empty; 
     lAppTest += (validationContext.ObjectType.GetProperty("LAMassing") != null) ? "X" : String.Empty; 
     lAppTest += (validationContext.ObjectType.GetProperty("LAScreening") != null) ? "X" : String.Empty; 
     lAppTest += (validationContext.ObjectType.GetProperty("LARock") != null) ? "X" : String.Empty; 
     lAppTest += (validationContext.ObjectType.GetProperty("LAEdging") != null) ? "X" : String.Empty; 
     lAppTest += (validationContext.ObjectType.GetProperty("LAWindbreak") != null) ? "X" : String.Empty; 
     lAppTest += (validationContext.ObjectType.GetProperty("LAGroundcover") != null) ? "X" : String.Empty; 
     lAppTest += (validationContext.ObjectType.GetProperty("LANaturalizing") != null) ? "X" : String.Empty; 
     lAppTest += (validationContext.ObjectType.GetProperty("LAOrchard") != null) ? "X" : String.Empty; 
     lAppTest += (validationContext.ObjectType.GetProperty("LATopiary") != null) ? "X" : String.Empty; 
     lAppTest += (validationContext.ObjectType.GetProperty("LAHerb") != null) ? "X" : String.Empty; 
     lAppTest += (validationContext.ObjectType.GetProperty("LAContainer") != null) ? "X" : String.Empty; 
     lAppTest += (validationContext.ObjectType.GetProperty("LABog") != null) ? "X" : String.Empty; 

     if (String.IsNullOrEmpty(lAppTest)) { 
      return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); 
     } 
     return ValidationResult.Success; 
    } 
} 

我打電話驗證作爲視圖模型的屬性:

[ConfirmLA(ErrorMessage = "You must select at least one Landscape Application!")] 
public string Landscape_Application { get; set; } 

在視圖模型的HTML代碼是一個簡單的重複:

<input type="checkbox" name="LAAccent" value="true" /> Accent/Feature<br /> 

裏面的一個表(即這15次,每個複選框一個)。

問題是,這總是拋出錯誤。我已經在驗證代碼本身內部進行了調試,並且它沒有通過它們的屬性名稱來識別任何複選框。換句話說,其中每一個:

lAppTest += (validationContext.ObjectType.GetProperty("LAAccent") != null) ? "X" : String.Empty; 

即使複選框被選中,也會解析爲空。我進一步證實了檢查值肯定存在於ActionResult的FormCollection中。就好像我的語法錯了或者某些東西,比如GetProperty方法沒有通過它們的屬性名稱找到這些複選框。我在這裏做錯了什麼?

回答

4

更改視圖模型是

[Required(ErrorMessage = "You must select at least one Landscape Application!")] 
public ICollection<string> LandscapeServices { get; set; } 

改變你的HTML是

<input type="checkbox" class="required-checkbox" name="LandscapeServices" value="LAAccent" /> Accent/Feature<br /> 
<input type="checkbox" class="required-checkbox" name="LandscapeServices" value="LAShade" /> Accent/Feature<br /> 
<input type="checkbox" class="required-checkbox" name="LandscapeServices" value="LAArticulation" /> Accent/Feature<br /> 
/*etc etc*/ 

當你點擊提交所有選定的值將被添加到屬性LandscapeServices。

請注意,這隻適用於服務器端驗證。如果你想要客戶端驗證,你將不得不使用你自己的javascript驗證函數在Required上創建一個擴展。

編輯 - 從SO answer

$(function(){ 
    $.validator.addMethod('required_group', function(value, element) { 
     var $module = $(element).parents('form'); 
     return $module.find('input.checkbox:checked').length; 
    }, 'Select at least one Service please'); 
    $.validator.addClassRules('required-checkbox', { 'required_group' : true }); 
+0

解決@ ScubaSteve的有關客戶端驗證評論我不得不調整這一點(變「的ICollection 」到「串[]」,並確保視圖模型傳遞作爲POST ActionResult中的一個參數),但是你讓我接觸到最佳解決方案。它還幫助我通過將處理端轉換爲「foreach」循環來縮短我的「接收者」代碼。謝謝,那太棒了! – Sylver 2012-02-29 14:10:55

+0

這適用於服務器端驗證,但不會像通常那樣自動添加客戶端驗證。 – ScubaSteve 2013-01-10 16:23:46

+0

@ScubaSteve有些事情需要留給問題的提問者去做。 – heads5150 2013-01-10 19:40:22

0

我不會使用這個屬性,除非你想做客戶端驗證。相反,我只是讓你的模型從IValidatableObject派生出來,然後在IsValid方法中進行驗證。更容易,也沒有遲到的約束。