2011-04-28 98 views
41

我需要驗證3個或更多輸入字段(至少需要一個)。例如,我有電子郵件,傳真,電話。MVC3不顯眼驗證組輸入

我需要至少一個填寫。我需要服務器和客戶端'不顯眼的驗證'。請幫忙。我看着「比較」方法,並嘗試修改它,但沒有運氣。請幫忙。 謝謝

+0

您將不得不編寫自定義驗證器以及一些js 從這裏開始http://haacked.com/archive/2009/11/19/aspnetmvc2-custom-validation.aspx – 2011-04-28 09:46:06

回答

83

你可以寫一個自定義屬性的一切:

public class AtLeastOneRequiredAttribute : ValidationAttribute, IClientValidatable 
{ 
    private readonly string[] _properties; 
    public AtLeastOneRequiredAttribute(params string[] properties) 
    { 
     _properties = properties; 
    } 

    protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     if (_properties == null || _properties.Length < 1) 
     { 
      return null; 
     } 

     foreach (var property in _properties) 
     { 
      var propertyInfo = validationContext.ObjectType.GetProperty(property); 
      if (propertyInfo == null) 
      { 
       return new ValidationResult(string.Format("unknown property {0}", property)); 
      } 

      var propertyValue = propertyInfo.GetValue(validationContext.ObjectInstance, null); 
      if (propertyValue is string && !string.IsNullOrEmpty(propertyValue as string)) 
      { 
       return null; 
      } 

      if (propertyValue != null) 
      { 
       return null; 
      } 
     } 

     return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); 
    } 

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) 
    { 
     var rule = new ModelClientValidationRule 
     { 
      ErrorMessage = ErrorMessage, 
      ValidationType = "atleastonerequired" 
     }; 
     rule.ValidationParameters["properties"] = string.Join(",", _properties); 

     yield return rule; 
    } 
} 

它可以用來裝飾你的視圖模型屬性之一(你想要得到強調,如果一個驗證失敗):

public class MyViewModel 
{ 
    [AtLeastOneRequired("Email", "Fax", "Phone", ErrorMessage = "At least Email, Fax or Phone is required")] 
    public string Email { get; set; } 
    public string Fax { get; set; } 
    public string Phone { get; set; } 
} 

,然後一個簡單的控制器:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     var model = new MyViewModel(); 
     return View(model); 
    } 

    [HttpPost] 
    public ActionResult Index(MyViewModel model) 
    { 
     return View(model); 
    } 
} 

呈現以下幾種觀點將採取定義自定義客戶端驗證適配器的保養要點:

@model MyViewModel 

<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script> 
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script> 
<script type="text/javascript"> 
    jQuery.validator.unobtrusive.adapters.add(
     'atleastonerequired', ['properties'], function (options) { 
      options.rules['atleastonerequired'] = options.params; 
      options.messages['atleastonerequired'] = options.message; 
     } 
    ); 

    jQuery.validator.addMethod('atleastonerequired', function (value, element, params) { 
     var properties = params.properties.split(','); 
     var values = $.map(properties, function (property, index) { 
      var val = $('#' + property).val(); 
      return val != '' ? val : null; 
     }); 
     return values.length > 0; 
    }, ''); 
</script> 

@using (Html.BeginForm()) 
{ 
    @Html.ValidationSummary(false) 

    <div> 
     @Html.LabelFor(x => x.Email) 
     @Html.EditorFor(x => x.Email) 
    </div> 

    <div> 
     @Html.LabelFor(x => x.Fax) 
     @Html.EditorFor(x => x.Fax) 
    </div> 

    <div> 
     @Html.LabelFor(x => x.Phone) 
     @Html.EditorFor(x => x.Phone) 
    </div> 

    <input type="submit" value="OK" /> 
} 

當然的自定義適配器和驗證規則應該被外部化到一個單獨的JavaScript文件,以避免與標記混合腳本。

+0

這非常有幫助。謝謝! – ShaneKm 2011-04-28 12:03:00

+0

出於某種原因,客戶端驗證不會觸發:(。?? – ShaneKm 2011-04-28 13:19:24

+2

@Shane Km,是在web.config中將ClientValidationEnabled屬性設置爲true還要確保您使用的jquery.validate插件版本與jquery兼容。有一箇舊版本與jQuery 1.5不兼容。 – 2011-04-28 13:23:27

2

由於您使用的是MVC 3,請參閱great video Brad Wilson對mvcConf的看法。有您需要創建客戶端+服務器不顯眼的驗證

5

我花了超過36小時爲什麼代碼並沒有爲我工作..最後,我發現在我的情況,我不應該在這行代碼使用屬性名稱

[AtLeastOneRequired("Email", "Fax", "Phone", ErrorMessage = "At least Email, Fax or Phone is required")] 

但我不得不使用HTMl元素ID來代替屬性名稱,它的工作方式就像魔術一樣。

在此發佈此信息,如果它可能有助於某人。

0

我發佈了answer這裏這個question這是類似於這一個。我的解決方案是使用由查詢驗證團隊創建的require_from_group(查看此folder)方法的更加流行的方式。

解決方案是通用的,因爲它適用於每個input類型textareaselect。您還可以指定需要填寫的有效字段的數量。

希望有幫助!

1

@Darin Kimitrov的解決方案可能是創建自定義驗證屬性的標準,可以與不顯眼的驗證一起使用。然而,使用自定義的驗證一個不引人注目的屬性驗證,也有一些缺點,如:

  • 的自定義驗證屬性只連接到一個屬性,所以如果有其它兩個輸入變化事件客戶端驗證將無法正常工作。
  • 錯誤消息與ValidationSummary正常工作,但如果你想要顯示整個組的錯誤信息(我認爲這是常態),那幾乎是不可能的。
  • 爲了避免第一個問題,我們可以將自定義驗證屬性添加到組中的每個元素,這將導致另一個問題:我們必須驗證組的所有元素,而不是停止在第一個無效的組元素。當然,第二個問題 - 每個元素的單獨錯誤消息仍然存在。

還有另一種方式來處理客戶端驗證輸入組,使用jquery驗證器中的組設置(https://jqueryvalidation.org/validate/#groups)。唯一的問題(也是最大的問題)是不引人注意的驗證默認不支持jquery驗證的組,所以我們必須自定義一點。

雖然這個答案很難「不顯眼」,但在我看來,如果您的最終目標是驗證一組輸入的同時使用Microsoft的不顯眼驗證程序庫,則需要嘗試擺脫不必要的代碼複雜性。

首先,因爲默認的jQuery驗證組的設置是不是在jQuery的不顯眼的驗證可用,我們必須覆蓋不顯眼的設置(REF。How can I customize the unobtrusive validation in ASP.NET MVC 3 to match my style?

$("form").on('submit', function() { 
    var form = this; 
    var validator = $(this).data("validator"); 

    if (validator.settings && !validator.settings.submitHandler) { 
     $.extend(true, validator.settings.rules, validationSettings.rules); 
     $.extend(true, validator.settings.groups, validationSettings.groups); 
     initGroups(validator); 

     var fnErrorReplacement = validator.settings.errorPlacement; 
     validator.settings.errorPlacement = function (error, element) { 
      validationSettings.errorPlacement(error, element, fnErrorReplacement, form); 
     } 
     validator.settings.submitHandler = formSubmitHandler; 
    } 
}); 

function formSubmitHandler(form) { 
    form.submit(); 
} 

之後,覆蓋不顯眼的驗證團體,規則和errorPlacement設置。

var validationSettings = { 
groups: { 
    checkboxgroup: "Email Fax Phone" 
}, 
rules: { 
    Email: { 
     required: function() { 
      return validateCheckboxGroup(["#Email", "#Fax", "#Phone"]); 
     } 
    }, 
    Fax: { 
     required: function() { 
      return validateCheckboxGroup(["#Email", "#Fax", "#Phone"]); 
     } 
    }, 
    Phone: { 
     required: function() { 
      return validateCheckboxGroup(["#Email", "#Fax", "#Phone"]); 
     } 
    } 
} 
, 
errorPlacement: function (error, element, fnUnobtrusive, form) { 
    switch (element.attr("name")) { 
     case "Email": 
     case "Fax": 
     case "Phone": 
      onGroupError(error, "CheckBoxGroup", form); 
      break; 
     default: 
      fnUnobtrusive(error, element); 
      break; 
    } 
} 
} 

function validateCheckboxGroup(names) { 
var result = true; 
$.each(names, function (index, value) { 
    if ($(value).is(":checked")) { 
     result = false; 
    } 
}); 
return result; 
} 

由於不顯眼的驗證程序不執行組的jQuery驗證器的設置,我們需要重用從兩個庫兩種功能:(1).split組名(從重複使用jQuery的驗證碼)和(2)追加錯誤元素沒有刪除'輸入驗證錯誤'類(重用函數onError從不顯眼的庫)。

function initGroups(validators) { 
validators.groups = {}; 
$.each(validators.settings.groups, 
    function (key, value) { 
     if (typeof value === "string") { 
      value = value.split(/\s/); 
     } 
     $.each(value, 
      function (index, name) { 
       validators.groups[name] = key; 
      }); 
    }); 
} 

function onGroupError(error, inputElementName, form) { 
var container = $(form).find("[data-valmsg-for='" + inputElementName + "']"), 
replaceAttrValue = container.attr("data-valmsg-replace"), 
replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null; 

container.removeClass("field-validation-valid").addClass("field-validation-error"); 
error.data("unobtrusiveContainer", container); 

if (replace) { 
    container.empty(); 
    error.appendTo(container); 
} 
else { 
    error.hide(); 
} 
} 

最後,使用HtmlExtensions.ValidationMessage創建複選框組的錯誤跨度。

@Html.ValidationMessage("CheckBoxGroup", new { @class = "text-danger" }) 

的「輸入驗證錯誤」的保持類是必要的,以便jquery的驗證器將驗證複選框組的所有3個元素(電子郵件,電話,傳真)作爲一個整體,而不是由一個驗證一個。不顯眼的驗證庫默認在函數onError中刪除這個類,所以我們必須在上面的函數onGroupError中將其定製爲showne。

相關問題