2012-12-06 31 views
2

我想創建一個自定義驗證使用IClientValidatableMVC3 ModelClientValidationRule比較2個不同的字段。添加所需的標誌

我有2個字段PhoneNumber和Mobile。我希望用戶能夠或者兩者兼而有之。只需要1個,但必須提供至少1個。

我設法得到這個至今

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


     rule.ValidationParameters.Add("phone", "PhoneNumber"); 
     rule.ValidationParameters.Add("mobile", "MobileNumber"); 

     yield return rule; 
    } 

這驗證適用於輸出html元素

<input data-val="true" data-val-length="Mobile number must be a maximum length of 14." data-val-length-max="14" data-val-required="Landline or mobile phone number is needed." data-val-required-required="MobileNumber" id="MobileNumber" name="MobileNumber" type="text" value=""> 
<input data-val="true" data-val-length="Landline number must be a maximum length of 14." data-val-length-max="14" data-val-required="Landline or mobile phone number is needed." data-val-required-required="PhoneNumber" id="PhoneNumber" name="PhoneNumber" type="text" value=""> 

現在我知道這不是完成這一切。但如果我嘗試點擊提交按鈕,驗證會在摘要中顯示2個驗證錯誤。

我有點卡在如何添加驗證器適配器。

到目前爲止....任何我知道它錯了,但

jQuery.validator.unobtrusive.adapters.add('required', 
     [$("#PhoneNumber").val(), $("#MobileNumber").val()], 
     function(options) { 
        options.rules['required'] = options.params; 
        options.messages['required'] = options.message; 
     }); 

回答

1

首先,你需要比Compare attribute類似的方式來創建自己的驗證屬性。

在此屬性中,您將指定其他依賴屬性,並且錯誤消息將被格式化以考慮屬性顯示名稱。

的屬性看起來像這樣(我不是太驕傲關於它的名字和默認的錯誤消息!):

public class SelectOneValidationAttribute : ValidationAttribute, IClientValidatable 
{ 
    private const string DefaultErrorMessage = "Please enter '{0}' or '{1}'."; 
    private string _otherFieldName; 

    public SelectOneValidationAttribute(String otherFieldName) 
     : base(DefaultErrorMessage) 
    { 
     _otherFieldName = otherFieldName; 
    } 

    public override string FormatErrorMessage(string name) 
    { 
     return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, _otherFieldName); 
    } 

    protected override DataAnnotationsValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     PropertyInfo otherPropertyInfo = validationContext.ObjectType.GetProperty(_otherFieldName); 
     if (otherPropertyInfo == null) 
     { 
      return new DataAnnotationsValidationResult("Unknown property " + _otherFieldName); 
     } 


     string strValue = value == null ? null : value.ToString(); 
     if(!String.IsNullOrEmpty(strValue)) 
      //validation succeeds as this field has been populated 
      return null; 

     object otherPropertyValue = otherPropertyInfo.GetValue(validationContext.ObjectInstance, null); 

     string strOtherPropertyValue = otherPropertyValue == null ? null : otherPropertyValue.ToString(); 
     if (!String.IsNullOrEmpty(strOtherPropertyValue)) 
      //validation succeeds as the other field has been populated 
      return null; 
     else 
      //validation failed, none of the 2 fields were populated 
      return new DataAnnotationsValidationResult(DefaultErrorMessage); 
    } 


    //Create the data attributes for the client to use 
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
    { 
     var rule = new ModelClientValidationRule 
     { 
      ValidationType = "selectone", 
      ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()) 
     }; 

     rule.ValidationParameters["otherfield"] = FormatPropertyForClientValidation(_otherFieldName); 

     yield return rule; 
    } 

    public static string FormatPropertyForClientValidation(string property) 
    { 
     return "*." + property; 
    } 
} 

所以,你可以用它在你的模型如:

public class YourModel 
{ 
    [SelectOneValidation("Phone")] 
    public string Mobile { get; set; } 

    [SelectOneValidation("Mobile")] 
    public string Phone { get; set; } 
} 

使用該代碼,錯誤消息「請輸入'Mobile'或'Phone'。」和「請輸入'電話'或'移動'。」將在服務器端驗證失敗時顯示。 (您可以設置相同的錯誤消息,例如「請輸入一個...」)

爲了添加客戶端驗證,您需要創建用於不顯眼驗證的適配器。 (請確保您添加它的地方不顯眼的驗證解析文檔之前,否則,你將需要手動解析它):

//Add an adaptor for our new jquery validator, that builds the optional parameters 
//for our validation code (the other field to look at) 
$.validator.unobtrusive.adapters.add("selectone", ["otherfield"], function (options) { 
    var prefix = getModelPrefix(options.element.name), 
     other = options.params.otherfield, 
     fullOtherName = appendModelPrefix(other, prefix), 
     element = $(options.form).find(":input[name=" + fullOtherName + "]")[0]; 

    setValidationValues(options, "selectone", element); 
}); 

這是使用中的少數幾個不顯眼的驗證庫定義類的實用功能:

function setValidationValues(options, ruleName, value) { 
    options.rules[ruleName] = value; 
    if (options.message) { 
     options.messages[ruleName] = options.message; 
    } 
} 

function getModelPrefix(fieldName) { 
    return fieldName.substr(0, fieldName.lastIndexOf(".") + 1); 
} 

function appendModelPrefix(value, prefix) { 
    if (value.indexOf("*.") === 0) { 
     value = value.replace("*.", prefix); 
    } 
    return value; 
} 

最後我創建了一個新的驗證規則。這是因爲儘管所需的驗證允許設置過濾表達式,因此當該表達式評估爲true時,該字段僅被標記爲有效,請參見required validation,但我們需要對onBlur驗證應用類似的修復程序,而不是等於規則。

驗證方法應用等於驗證的所述修復,然後僅在其他相關字段上使用依賴選擇器調用所需的規則,因此只有在字段爲空且依賴項有空時,所需的驗證纔會返回false沒有被填滿。

$.validator.addMethod("selectone", function (value, element, param) { 
    // bind to the blur event of the target in order to revalidate whenever the target field is updated 
    // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead 
    var otherField = $(param); 
    if (this.settings.onfocusout) { 
     otherField.unbind(".validate-selectone").bind("blur.validate-selectone", function() { 
      $(element).valid(); 
     }); 
    } 

    var otherFieldBlankFilter = ":input[name=" + otherField[0].name + "]:blank"; 
    return $.validator.methods.required.call(this, value, element, otherFieldBlankFilter); 
}); 

如果你不介意這件事,就好像你在表單提交僅在驗證,你可以只寫直接使用所需的規則的適配器:

$.validator.unobtrusive.adapters.add("selectone", ["otherfield"], function (options) { 
    var prefix = getModelPrefix(options.element.name), 
     other = options.params.otherfield, 
     fullOtherName = appendModelPrefix(other, prefix), 
     element = $(options.form).find(":input[name=" + fullOtherName + "]")[0]; 

    setValidationValues(options, "required", ":input[name=" + fullOtherName + "]:blank"); 
}); 

與所有這到位,你的驗證應該工作。如果兩者均爲空,並且您嘗試提交,則兩個字段都將顯示錯誤消息。如果您隨後在其中一個地方輸入內容並將其標記出來,則應刪除這兩個錯誤消息。

您應該也可以根據需要調整它,因爲您可以修改驗證屬性,不顯眼的適配器和驗證規則。