Grupo de validação não intrusivo MVC3 de inputs

Eu preciso validar 3 ou mais campos de input (requeridos pelo menos um). Por exemplo, eu tenho e-mail, fax, telefone.

Eu preciso que pelo menos UM seja preenchido. Eu preciso da validação discreta do servidor e do cliente. por favor ajude. Eu olhei para o método “Compare” e tentei modificá-lo, mas sem sorte. por favor ajude. obrigado

Você poderia escrever um atributo personalizado:

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 GetClientValidationRules(ModelMetadata metadata, ControllerContext context) { var rule = new ModelClientValidationRule { ErrorMessage = ErrorMessage, ValidationType = "atleastonerequired" }; rule.ValidationParameters["properties"] = string.Join(",", _properties); yield return rule; } } 

que pode ser usado para decorar uma das propriedades do modelo de visualização (aquela que você deseja destacar se a validação falhar):

 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; } } 

e depois um simples controlador:

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

Renderizando a visualização a seguir, que cuidará da definição do adaptador validador do lado do cliente customizado:

 @model MyViewModel    @using (Html.BeginForm()) { @Html.ValidationSummary(false) 
@Html.LabelFor(x => x.Email) @Html.EditorFor(x => x.Email)
@Html.LabelFor(x => x.Fax) @Html.EditorFor(x => x.Fax)
@Html.LabelFor(x => x.Phone) @Html.EditorFor(x => x.Phone)
}

É claro que o adaptador personalizado e a regra do validador devem ser externalizados em um arquivo javascript separado para evitar misturar scripts com marcações.

Passei mais de 36 horas porque o código não funcionou para mim .. No final, descobri que no meu caso, eu não deveria usar os nomes de propriedade nesta linha de código

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

Mas eu tive que usar os IDs dos elementos HTMl no lugar dos nomes das propriedades e funcionou como mágica.

Postando isso aqui, se isso puder ajudar alguém.

Como você está usando o MVC 3, dê uma olhada no excelente vídeo que o Brad Wilson tinha no mvcConf. Há tudo o que você precisa para criar Validação discreta de cliente + servidor

A solução de @Darin Kimitrov é provavelmente o padrão de criação de um atributo de validação personalizado que funciona com validação discreta. No entanto, usar atributos de validação personalizados para validação discreta tem algumas desvantagens, como:

  • O atributo de validação customizado é anexado apenas a uma propriedade, portanto, a validação do cliente não funcionará se houver um evento de mudança nas outras duas inputs.
  • A mensagem de erro funciona bem com o ValidationSummary, mas se você quiser exibir uma mensagem de erro para todo o grupo (que eu acho que é a norma), seria quase impossível.
  • Para evitar o primeiro problema, podemos adicionar um atributo de validação personalizado a cada elemento no grupo, o que causará outro problema: temos que validar todos os elementos do grupo, em vez de parar no primeiro elemento de grupo inválido. E, claro, o segundo problema – mensagens de erro separadas para cada elemento – ainda permanece.

Há outra maneira de lidar com a validação do cliente de grupos de inputs, usando a configuração de grupos no validador de jquery ( https://jqueryvalidation.org/validate/#groups ). O único problema (e grande) é que a validação não intrusiva não suporta grupos de validação de jquery por padrão, então temos que personalizar um pouco.

Embora esta resposta dificilmente seja “discreta”, na minha opinião, vale a pena tentar livrar-se de complicações desnecessárias de código, se seu objective final é validar um grupo de inputs enquanto estiver usando a biblioteca de validador discreto da Microsoft.

Em primeiro lugar, como as configurações de grupos do validador de jquery padrão não estão disponíveis no validador não intrusivo de jquery, temos que replace as configurações não-intrusivas (ref. Como posso personalizar a validação discreta no ASP.NET MVC 3 para corresponder ao meu estilo? )

 $("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(); } 

Depois disso, substitua os grupos, as regras e as configurações de errorPlacement do validador não intrusivo.

 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; } 

Como o validador não intrusivo não implementa a configuração de grupos do validador jquery, precisamos reutilizar duas funções das duas bibliotecas para: (1) .split nomes de grupos (reutilizando código do jquery validator) e (2) acrescentar elemento de erro sem remover ‘input- validation-error ‘class (reutilizando a function onError da biblioteca não intrusiva).

 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(); } } 

Por fim, use HtmlExtensions.ValidationMessage para criar intervalo de erro do grupo de checkboxs de seleção.

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

A manutenção da class “input-validation-error” é necessária, para que o validador de jquery valide todos os 3 elementos (E-mail, Telefone, Fax) do grupo de checkboxs de seleção como um todo, em vez de validar um por um. A biblioteca de validação discreta remove essa class por padrão na function onError, então temos que customizar isso como mostrado na function onGroupError acima.