Conditional Data Annotation MVC4

Asked

Viewed 2,258 times

2

I researched pacas here and did not find a solution for what I wanted. I wonder if anyone has done something similar in MVC4.

Model:

public class Trabalhador
{

    [Required(ErrorMessage = "*")]
    public int Id { get; set; }

    [Required(ErrorMessage = "*")]
    public String Nome { get; set; }

    public String Aposentado { get; set; }

    [Requerido caso o Aposentado seja "S"]
    public DateTime DataAposentadoria { get; set; }
}

View:

@Html.TextBoxFor(model => model.Id)
@Html.ValidationMessageFor(model => model.Id)

@Html.TextBoxFor(model => model.Nome)
@Html.ValidationMessageFor(model => model.Nome)

@Html.TextBoxFor(model => model.Aposentado)
@Html.ValidationMessageFor(model => model.Aposentado)

@Html.TextBoxFor(model => model.DataAposentadoria)
@Html.ValidationMessageFor(model => model.DataAposentadoria)

Here is the X of Questao, I in my form desire all fields, however I want to force me to type the Retirement Date only in the case of a specific value in the Retired attribute (which in case would be "S" or any other value I want). I searched several posts right here in Stack, but none of the models worked.

https://stackoverflow.com/questions/3713281/attribute-dependent-on-another-field/5079585#5079585 http://miroprocessordev.blogspot.com.br/2012/08/aspnet-mvc-conditional-validation-using.html https://stackoverflow.com/questions/2417113/asp-net-mvc-conditional-validation http://blogs.msdn.com/b/simonince/archive/2010/06/04/conditional-validation-in-mvc.aspx

  • Maybe the attribute RequiredIf present in this SOEN reply help you: http://stackoverflow.com/a/15975880/195417

  • Already put the solution for you.

4 answers

1

My solution:

[AttributeUsageAttribute(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
public class DataAposentadoria : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var property = validationContext.ObjectInstance.GetType().GetProperty("Aposentado");

        if (property == null)
            return new ValidationResult("Propriedade desconhecida: 'Aposentado'");

        var propertyValue = property.GetValue(validationContext.ObjectInstance, null);

        if (propertyValue != null && propertyValue.ToString() == "S" && value == null)
        {
            return new ValidationResult("Data de aposentadoria deve ser preenchida!");
        }
        return ValidationResult.Success;
    }
}

To use:

public String Aposentado { get; set; }

[DataAposentadoria]
public DateTime? DataAposentadoria { get; set; }

Explaining, when he enters the property, he will try to find out if the "Retired" property exists, if it exists he takes the value and validates.

Of course you can increment to place a dynamic property.

  • I tested this solution here and also does not force validation, if the condition is met.

0

Gentlemen, the Fccdias solution worked, but I had to make a small change, I did not want to change its code, because I could not understand well that block of Javascript, but the only change I made was in the last line: Didn’t Work: Return $(params.item). val() == params.value && value != '&& value.length == 10; Worked: Return "";

Thank you all for your help;

0

You can implement an attribute that performs a custom validation in the same way as the Required, but only when the condition is satisfied, and use this attribute instead of the Required.

In this attribute implement the interface IClientValidatable to be able to validate in the client, when using nonobstructive validation, and implement a validation implementation with javascript.

An example is in this SOEN response:

I adapted the attribute of the answer presented above to have non-aggressive validation in the client:

public class RequiredIfAttribute : RequiredAttribute, IClientValidatable
{
    private String PropertyName { get; set; }
    private Object Comparand { get; set; }

    public RequiredIfAttribute(String propertyName, Object comparand)
    {
        PropertyName = propertyName;
        Comparand = comparand;
    }

    protected override ValidationResult IsValid(object value, ValidationContext context)
    {
        var instance = context.ObjectInstance;
        var type = instance.GetType();
        var proprtyvalue = type.GetProperty(PropertyName).GetValue(instance, null);

        if (proprtyvalue.ToString() == Comparand.ToString())
        {
            var result = base.IsValid(value, context);
            return result;
        }

        return ValidationResult.Success;
    }

    IEnumerable<ModelClientValidationRule> IClientValidatable.GetClientValidationRules(
        ModelMetadata metadata,
        ControllerContext context)
    {
        var requiredIfRule = new ModelClientValidationRule();
        requiredIfRule.ErrorMessage = this.ErrorMessageString;
        requiredIfRule.ValidationType = "requiredif";
        requiredIfRule.ValidationParameters.Add("propertyname", this.PropertyName);
        requiredIfRule.ValidationParameters.Add("comparand", this.Comparand);
        yield return requiredIfRule;
    }
}

Create a javascript file, and include it on the page with the field to be validated:

$.validator.addMethod("requiredif", function (value, element, params) {
    return $(params.propertyname).val() == params.comparand
        ? value != null && value != "" && value != undefined
        : true;
});

$.validator.unobtrusive.adapters.add(
    "requiredif",
    ["propertyname", "comparand"],
    function (options) {
        options.rules["propertyname"] = "#" + options.params.propertyname;
        options.rules["comparand"] = options.params.comparand;
        options.messages["requiredif"] = options.message;
    });

And wear it like this:

public class Trabalhador
{
    [Required(ErrorMessage = "*")]
    public int Id { get; set; }

    [Required(ErrorMessage = "*")]
    public String Nome { get; set; }

    public String Aposentado { get; set; }

    [RequiredIf("Aposentado", "S")]
    public DateTime DataAposentadoria { get; set; }
}

Reference:

I couldn’t determine the authorship of the attribute RequiredIf... searching on Google for RequiredIfAttribute RequiredAttribute returns numerous sources where this code is used. I will search further, and if found, I reference here. If someone finds the author, please feel free to edit the reply, or make a comment.

  • Thank you brother, but I had already tried this solution, exactly as Oce posted, however the form does not force me to validate the fields requeredif even meeting the condition.

  • Are you talking about validating on the client before submitting the form? ... the way I posted it here, it’s a server validation, not the client.

  • Yes, it would be exactly the client validation as it is done in the other attributes, the question is why the [Required(Errormessage = "*")] public String Name { get; set; } is validated and the [Requiredif("Retired", "S")] public Datetime Dataretirement { get; set; } is not validated =/

  • I edited the response with an implementation that allows validation in the client.

  • Miguel, thanks for the help, but it hasn’t worked yet, my Dropdown has the option of S or N, when I put in S it forces the validation, put a "T" just to test and even changing the value of the drop to T the validation is still forced, Since this validation should be enforced only in the "S" case, weird, should I change anything in the JS you went through? because the same is already on the screen and still nothing, I should include still some JS libraries?

  • My mistake... validation was being done wrong. Corrected.

  • You managed to solve your problem?

  • Still ñ miguel, continues in the same, the validation is forced even if I play a different value of "S" ("T" in the case only for test), I will try the solution proposed below by Fccdias.

  • I have no way to run this right now, to debug and see what’s wrong. The @Fccdias solution is very similar, with some small differences... maybe it works.

  • Thank you gentlemen, but unfortunately it did not work, I will solve in a way that I would not like, using Jquery and checking field by field, will not get a stylish solution, but will solve, although I would prefer it to be using Data Annotation.

  • Man, I’m sure you can do something like... when you get home, I swear I’ll try to create a minimum functional example. = D

Show 6 more comments

0

Create a class that will be the Attribute, with inheritance in the abstract class Validationattribute this being server validation, and implements the interface Iclientvalidatable to create customer validation.

Class: Attribute

public class ValidationIfAposentado : ValidationAttribute, IClientValidatable
{
    public String CompareProperty {get;set;}
    public string CompareValue { get; set; }
    public ValidationIfAposentado(String CompareProperty, String CompareValue)
    {
        this.CompareProperty = CompareProperty;
        this.CompareValue = CompareValue;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        PropertyInfo propertyInfo = validationContext.ObjectInstance.GetType().GetProperty(CompareProperty);
        if (propertyInfo != null)
        {
            object valor = propertyInfo.GetValue(validationContext.ObjectInstance, null);
            if (!(valor != null && CompareValue.Equals(valor.ToString())))
            {  
               return new ValidationResult(this.ErrorMessage);                   
            }
        }
        return ValidationResult.Success;
    }
    IEnumerable<ModelClientValidationRule> IClientValidatable.GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var erro = new ModelClientValidationRequiredRule(this.ErrorMessage);
        erro.ValidationType = "validationifaposentado";
        erro.ValidationParameters.Add("item", CompareProperty);
        erro.ValidationParameters.Add("value", CompareValue);            
        yield return erro;
    }
}

Class: Laborer

public class Trabalhador
{
    [Required(ErrorMessage = "*")]
    public int Id { get; set; }

    [Required(ErrorMessage = "*")]
    public String Nome { get; set; }

    [MinLength(1), MaxLength(1)]
    public String Aposentado { get; set; }

    [ValidationIfAposentado("Aposentado", "S", ErrorMessage="Como é aposentado digite a data de aposentadoria")]
    [DataType(DataType.Date)]
    public DateTime? DataAposentadoria { get; set; }
}

In class Trabalhador, was made an addition of ? or System.Nullable in the DataAposentadoria, since the same will only have value if the Aposentado be equal "S" if I don’t record the DataAposentadoria as NULL.

With the Attribute Validationifaposentado it will check and validate on the server.

For validation via client (Javascript) this javascript should be implemented right below that is corresponding to server validation.

Javascript: Code using these references from jQuery, jQuery.Validation and jQuery.Unobtrusive.

<script src="/Scripts/jquery-2.1.0.js"></script>
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>
<script> 
    jQuery.validator.unobtrusive.adapters.add("validationifaposentado", ["item", "value"],
        function (options) {
            options.rules['validationifaposentado'] = {
                item: "#" + options.params.item,
                value: options.params.value, 
            }
            options.messages["validationifaposentado"] = options.message;                
        });
    jQuery.validator.addMethod("validationifaposentado", function (value, element, params) {            
        if ($(params.item).val() === undefined || $(params.item).val() == '') {
            return true;
        }       
        return $(params.item).val() == params.value && value != '' && value.length == 10;
    });
</script>

Browser other questions tagged

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