2011-04-28 65 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。

相关问题