【发布时间】:2011-04-28 09:15:08
【问题描述】:
我需要验证 3 个或更多输入字段(至少需要一个)。例如,我有电子邮件、传真、电话。
我至少需要填写一个。我需要服务器和客户端“不显眼的验证”。请帮忙。我研究了“比较”方法并尝试修改它,但没有运气。请帮忙。 谢谢
【问题讨论】:
-
您必须编写自定义验证器以及一些 js 从这里开始haacked.com/archive/2009/11/19/…
我需要验证 3 个或更多输入字段(至少需要一个)。例如,我有电子邮件、传真、电话。
我至少需要填写一个。我需要服务器和客户端“不显眼的验证”。请帮忙。我研究了“比较”方法并尝试修改它,但没有运气。请帮忙。 谢谢
【问题讨论】:
你可以写一个自定义属性:
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 文件中,以避免脚本与标记混合。
【讨论】:
ClientValidationEnabled 属性是否在 web.config 中设置为 true?还要确保您使用的是与 jquery 兼容的 jquery.validate 插件版本。有一个旧版本与 jQuery 1.5 不兼容。
[MultiFieldRequired(new string[3]{"Phone1", "Phone2", "Phone3"}, ErrorMessage ="Phone# required")] ------代码只接受一个数组。我不确定人们如何使用这些逗号分隔的字符串并使其正常工作。
我花了超过 36 个小时为什么代码对我不起作用。最后,我发现在我的情况下,我不应该在这行代码中使用属性名称
[AtLeastOneRequired("Email", "Fax", "Phone", ErrorMessage = "At least Email, Fax or Phone is required")]
但我必须使用 HTMl 元素 ID 来代替属性名称,它就像魔术一样工作。
如果对某人有帮助,请在此处发布。
【讨论】:
由于您使用的是 MVC 3,请查看 great video Brad Wilson 在 mvcConf 上发表的文章。创建客户端+服务器不显眼验证所需的一切都应有尽有
【讨论】:
@Darin Dimitrov 的解决方案可能是创建与不显眼的验证一起使用的自定义验证属性的标准。但是,使用自定义验证属性进行不显眼的验证有一些缺点,例如:
还有另一种处理输入组客户端验证的方法,使用 jquery 验证器 (https://jqueryvalidation.org/validate/#groups) 中的组设置。唯一的问题(也是一个大问题)是默认情况下不显眼的验证不支持 jquery 验证的组,所以我们必须自定义一点。
虽然这个答案很难“不引人注目”,但在我看来,如果您的最终目标是在使用 Microsoft 不引人注目的验证器库时验证一组输入,那么尝试摆脱不必要的代码复杂性是值得的。
首先,由于默认 jquery 验证器的组设置在 jquery 非侵入式验证器中不可用,我们必须覆盖非侵入式设置(参考。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;
}
由于unobtrusive validator没有实现jquery validator的groups设置,我们需要复用两个库中的两个函数:(1).split group names(复用jquery validator的代码)和(2) append error element without remove 'input-validation-error' 类(重用函数 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" })
保留“input-validation-error”类是必要的,这样jquery验证器将验证复选框组的所有3个元素(电子邮件、电话、传真)作为一个整体,而不是一个一个地验证。不显眼的验证库默认在函数 onError 上删除这个类,所以我们必须自定义它,如上面的函数 onGroupError 所示。
【讨论】: