2011-08-05 40 views
3

我正在嘗試編寫一個自定義驗證屬性,該屬性將根據模型的布爾屬性有條件地要求字段。如何獲取MVC3中的自定義IClientValidatable使用的模型屬性的id

我有我的屬性實現IClientValidatable。我有要檢查的屬性的名稱,但我不知道如何獲取目標屬性的客戶端ID。

public IEnumerable<ModelClientValidationRule> 
         GetClientValidationRules(ModelMetadata metadata, 
               ControllerContext context) 
{ 
    var clientTarget = ?????; 
    var rule = new ModelClientValidationRule() 
    { 
     ErrorMessage = 
      FormatErrorMessage(metadata.DisplayName ?? metadata.PropertyName), 
     ValidationType = "requiredif" 
    }; 

    rule.ValidationParameters["target"] = clientTarget; 

    yield return rule; 
} 

的JavaScript:

$.validator.addMethod("requiredif", function (value, element, target) 
{ 
    //check on value of target 
}); 

$.validator.unobtrusive.adapters.addSingleVal("requiredif", "target"); 

我怎樣才能得到目標物業的客戶ID,以便客戶端的JavaScript可以在值檢查?

+0

它看起來像[MVC萬無一失驗證](https://foolproof.codeplex.com/SourceControl/latest#Foolproof/RequiredIf.cs)所做的那樣是完全忽略該ID,而是傳遞一個生成的密鑰值對非常識別該字段。 – KyleMit

回答

-2

看看這個article。它討論了服務器端的DataAnnotation驗證,並且還演示瞭如何通過實現IClientVaildatable並在客戶端編寫一些jQuery來在客戶端掛接這些屬性。

+2

我可能是錯誤的,但雖然這是關於驗證器邏輯的精彩文章,但它只是假設客戶端字段名稱將與服務器端屬性名稱相同。當你的模型編輯器嵌套在另一個編輯器中時,這不會解釋MVC添加的前綴 –

+0

是的,你是正確的前綴。但是您也可以將其作爲驗證參數發送。前綴只在客戶端腳本中很重要。所以在客戶端,您可以在執行驗證時檢查是否存在前綴 –

+0

如何查找前綴是什麼,以便客戶端代碼可以識別正確的元素以驗證 –

1

這只是使用MVC5進行測試,但我懷疑它沒有從MVC3改變。

這是一種醜陋的,但它似乎工作。有兩個假設:

  1. MVC框架實際上總是通過在ViewContextGetClientValidationRules(....)ControllerContext說法。在我的所有測試中,情況一直如此,但我無法保證100%。
  2. 的其他財產是在同一個模型級的水平(而不是複雜類型的實例的子屬性)

如果這兩個假設持有的話,那麼下面似乎工作:

0

這個工作對我來說,可能需要一些調整,但你可以得到的想法:

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

    string depProp = BuildDependentPropertyId(metadata, context as ViewContext); 

    // find the value on the control we depend on; 
    // if it's a bool, format it javascript style 
    // (the default is True or False!) 
    string targetValue = (this.TargetValue ?? "").ToString(); 
    if (this.TargetValue != null && this.TargetValue.GetType() == typeof(bool)) 
     targetValue = targetValue.ToLower(); 

    rule.ValidationParameters.Add("dependentproperty", depProp); 
    rule.ValidationParameters.Add("targetvalue", targetValue); 

    yield return rule; 
} 

private string BuildDependentPropertyId(ModelMetadata metadata, ViewContext viewContext) 
{ 
    return QualifyFieldId(metadata, this.DependentProperty, viewContext); 
} 

屬性的屬性,如:

[RequiredIf("SelectedPeriod", "DateRange", ErrorMessageResourceName = "FromDateRequired", ErrorMessageResourceType = typeof(Common))] 
public DateTime? StartDate { get; set; } 
//dependent property 
public string SelectedPeriod { get; set; } 

這是怎麼弄的現場ID:

protected string QualifyFieldId(ModelMetadata metadata, string fieldId, ViewContext viewContext) 
{ 
    // build the ID of the property 
    string depProp = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(fieldId); 

    var thisField = metadata.PropertyName + "_"; 
    if (depProp.StartsWith(thisField)) 
    // strip it off again 
    depProp = depProp.Substring(thisField.Length); 
else if (null != metadata.ContainerType && !string.IsNullOrEmpty(metadata.ContainerType.Name)) 
    { 
     depProp = metadata.ContainerType.Name + "_" + fieldId; 
    } 
    return depProp; 
} 
5

我把內森的出色答卷,加入了一些意見,幷包裹在一個名爲GetHtmlId擴展方法,所以現在我可以使用像這樣的代碼來獲取任何其他元素的HTML ID在同一頁上:

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

     // Find the value on the control we depend on... 
     string depProp = this.GetHtmlId(metadata, context, this.DependentPropertyName); 

     rule.ValidationParameters.Add("dependentproperty", depProp); 

     yield return rule; 
    } 

而這裏的擴展方法:

using System; 
using System.Collections.Generic; 
using System.Web.Mvc; 

namespace sbs.Lib.Web.ValidationAttributes 
{ 
    public static class IClientValidatableExtensions 
    { 
     /// <summary> Returns the HTML ID of the specified view model property. </summary> 
     /// <remarks> Based on: http://stackoverflow.com/a/21018963/1637105 </remarks> 
     /// <param name="metadata"> The model metadata. </param> 
     /// <param name="viewContext"> The view context. </param> 
     /// <param name="propertyName"> The name of the view model property whose HTML ID is to be returned. </param> 
     public static string GetHtmlId(this IClientValidatable me, 
             ModelMetadata metadata, ControllerContext context, 
             string propertyName) 
     { 
      var viewContext = context as ViewContext; 

      if (viewContext == null || viewContext.ViewData.TemplateInfo.HtmlFieldPrefix == string.Empty) { 
       return propertyName; 
      } else { 
       // This is tricky. The "Field ID" returned by GetFullHtmlFieldId is the HTML ID 
       // attribute created by the MVC view engine for the property whose validator is 
       // being set up by the caller of this routine. This code removes the property 
       // name from the Field ID, then inserts the specified property name. 
       // Of course, this only works for elements on the same page as the caller of 
       // this routine! 
       string fieldId = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(""); 
       fieldId = fieldId.Remove(fieldId.LastIndexOf("_")); 
       return fieldId + "_" + propertyName; 
      } 
     } 
    } 
} 
+0

如果fieldId不包含下劃線有問題,必須添加一個檢查以防止發生異常 –

相關問題