Validation of two fields with jQuery.validate and Dataannotations

Asked

Viewed 483 times

4

Good afternoon, you guys,

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

Follows 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>

}

2 answers

6


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

The IValidatableObject is an interface that serves precisely for this, valida obejtos.

To use, simply 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 his controller, just check if the ModelState is valid, the same way you should be doing.

Rebound that is also possible to do by attribute, but as it is only for a Model, I see no need.

  • Thank you very much Randrade, I will adapt the code here...

2

I already 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; }
  • I tried this way tbm, but the jQuery validate does not show the message, nor went to the breakpoint.

  • In your view you have this @Html.Validationsummary(true) ?

  • No, you need to have that code?

  • You have this code: @Html.Antiforgerytoken().

  • It serves to indicate where the error message appears, for example, if you leave "true" and in Modelstate you by Addmodelerror("Name", "Fill in the name field") when the name is not filled in the error message will appear next to the Name field.

  • But as messages from other fields appear normally?

  • In the other fields you decorate the property in the Model with [Required]?

  • Yes, then validate already creates with htmlhelper?

  • Exactly. You need it to validate these two fields before the user sends the information or it can be after he has already given a Ubmit?

  • I get it. I think before would be better before, but, in the desperation that I’m either kkk

  • Then I will edit my reply with a piece of code that I use in my application

  • All right, thank you very much!

  • It worked Felipe, Thank you so much! Saved me man.

  • 1

    Not at all. Dispose.

Show 9 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.