Validation of two fields with jQuery.validate and DataAnnotations

4

Good afternoon guys,

Next, I need to validate if one of two fields is filled, I tried to create an Attribute function with ValidationAttribute but it did not validate correctly, I think jQuery.validate does not recognize it.

Follow the codes:

Class ValidationAttribute

public class VerifyPhoneAttribute : ValidationAttribute, IClientValidatable
{
    private readonly string OtherPropertyName;

    public VerifyPhoneAttribute(string otherPropertyName)
        : base("Um dos telefones deve estar preenchido.")
    {
        OtherPropertyName = otherPropertyName;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var otherPropertyInfo = validationContext.ObjectType.GetProperty(OtherPropertyName);
        string otherPhone = otherPropertyInfo.GetValue(validationContext.ObjectInstance, null).ToString(), thisDate = value.ToString();

        if (string.IsNullOrEmpty(otherPhone) && string.IsNullOrEmpty(thisDate))
            return new ValidationResult("Um dos telefones deve estar preenchido.");

        return null;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRegexRule(FormatErrorMessage(metadata.DisplayName), OtherPropertyName);

        return new List<ModelClientValidationRule>() { rule };
    }
}

Model

[MaxLength(15)]
    [Display(Name = "Primeiro telefone")]
    [VerifyPhone("client_phone2")]
    public string client_phone1 { get; set; }

    [MaxLength(15)]
    [Display(Name = "Segundo telefone")]
    public string client_phone2 { get; set; }

View

<div class="col-md-2">
                            @Html.LabelFor(model => model.client_phone1)
                            @Html.EditorFor(model => model.client_phone1, new { htmlAttributes = new { @class = "form-control input-sm input-phone input-phone1" } })
                            @Html.ValidationMessageFor(model => model.client_phone1, "", new { @class = "text-danger" })
                        </div>
                        <div class="col-md-2">
                            @Html.LabelFor(model => model.client_phone2)
                            @Html.EditorFor(model => model.client_phone2, new { htmlAttributes = new { @class = "form-control input-sm input-phone input-phone2" } })
                            @Html.ValidationMessageFor(model => model.client_phone2, "", new { @class = "text-danger" })
                        </div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")

<script>
    $.validator.unobtrusive.adapters.addSingleVal("VerifyPhone", "phone2");
    $.validator.addMethod("VerifyPhone", function (value, element, phone2) {
        return value.match(phone2);
    });
</script>

}

    
asked by anonymous 14.09.2016 / 19:15

2 answers

6

There is an easier way to do this, which is by using the IValidatableObject .

The IValidatableObject is an interface that serves just that, validates objects.

To use, just change your template to the following:

//Adicione a interface IValidatableObject
public class Cliente : IValidatableObject
{
    [MaxLength(15)]
    [Display(Name = "Primeiro telefone")]
    public string client_phone1 { get; set; }

    [MaxLength(15)]
    public string client_phone2 { get; set; }

    //Aqui que a "mágica" ocorre
    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (string.IsNullOrWhiteSpace(client_phone1) && string.IsNullOrWhiteSpace(client_phone2))
        {
            yield return new ValidationResult("Um dos telefones deve estar preenchido.", new[] { "client_phone1", "client_phone2" });
        }
    }
}

Note that in the line below I add the message and in which fields ( ValidationMessageFor() ) that the message should appear.

   yield return new ValidationResult("Um dos telefones deve estar preenchido.", new[] { "client_phone1", "client_phone2" });

In your controller , just check that ModelState is valid, just as you should already be doing.

    
14.09.2016 / 20:57
2

I've had this problem once and solved using an IF

public ActionResult NomeAction(Model model)
{
    if(string.IsNullOrWhiteSpace(model.client_phone1) && string.IsNullOrWhiteSpace(model.client_phone2))
    {
         ModelState.AddModelError("Pelo menos 1 dos 2 campos devem ser preenchidos")
    }
}

Edit 1

Controller

public ActionResult Create(Model model)
{
    if(ModelState.IsValid)
    {
        if (string.IsNullOrWhiteSpace(model.client_phone1) && string.IsNullOrWhiteSpace(model.client_phone2))
        {                 
             ModelState.AddModelError("", "Ao menos um dos campos de telefone devem ser preenchidos.");
             return View("Create", model);
        }                        
    }
}

View

@using (Html.BeginForm("Create", "Controller", FormMethod.Post)) {
    @Html.ValidationSummary(false)
    @Html.AntiForgeryToken()

    <fieldset>
        <legend></legend>       
        <div class="editor-label">
             <strong>Primeiro Telefone</strong>
        </div>
        @Html.EditorFor(a => a.client_phone1)
        @Html.ValidationMessageFor(a => a.client_phone1) 

        <div class="editor-label">
             <strong>Segundo Telefone</strong>
        </div>
        @Html.EditorFor(a => a.client_phone2)
        @Html.ValidationMessageFor(a => a.client_phone2)
   </fieldset>

Model

[MaxLength(15)]    
[Display(Name = "Primeiro telefone")]
//Essa linha não é necessária
//[VerifyPhone("client_phone2")]
public string client_phone1 { get; set; }

[MaxLength(15)]
[Display(Name = "Segundo telefone")]
public string client_phone2 { get; set; }
    
14.09.2016 / 19:42