0

I have written an attribute before, but I I have not written a validation attribute before. I am seriously confused about how it all works together. I have read most of the tutorials online about how to go about accomplishing this. But I am left with a couple of questions to ponder.

Keep in mind that I am trying to write a requiredIf attribute that will only call a remote function if a certain Jquery variable is set... which incidentally is a variable that is pulled from view state... I guess I could make that part of my view model. But I digress

1) The C# code is slightly confusing. I know my attribute should extend the ValidationAttribute, IClientValidatable class and interface respectively. But I am a little confused about what each of the overidden methods should be doing? I am trying to write a requiredIf, how does overwriting these methods help me accomplish this goal?

2) If the variable is not there, I simply don't want the remote function to attempt to validate the field. I don't want any message to pop up on my form. Alot of the tutorials seem to revolve around that.

3) I am confused about what I need to do with the jquery to add this function to the view... What do I need to add to the JQuery to get this thing to work... It seems like a lot of extra coding when I could simply just type up a jquery function that did the same thing with just the same ore less coding... I know it also adds server side validation which is good. But still...

Here is what I have for my jquery side of this equation...

(function ($) {
    $validator.unobtrusive.adapters.addSingleVal("requiredifattribute", "Dependent");
    $validator.addMethod("requiredifattribute", function (value, element, params) {
        if (!this.optional(element)) {
            var otherProp = $('#' + params)
            return (otherProp.val() != value);
        }
        return true;
    })
}(jQuery));

Here is my Attribute (which is basically carbon copied out of one the required if tutorials... I know I need to customize it more, but once I get a better idea of what every piece is doing I will do that...

[AttributeUsage(AttributeTargets.Property)]
public class RequiredIfAttribute  : ValidationAttribute, IClientValidatable {
    private const string errorMessage = "The {0} is required.";
    //public string 
    private RequiredAttribute innerAttribute = new RequiredAttribute();
    public string DependentProperty { get; set; }
    public object TargetValue { get; set; }

    public RequiredIfAttribute(string dependentProperty, object targetValue){
        this.DependentProperty = dependentProperty;
        this.TargetValue = targetValue;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext) {
        var field = validationContext.ObjectInstance.GetType().GetProperty(DependentProperty);
        if (field != null) {
            var dependentValue = field.GetValue(validationContext.ObjectInstance, null);
            if ((dependentValue == null && TargetValue == null) || (dependentValue.Equals(TargetValue))) {
                if (!innerAttribute.IsValid(value))
                    return new ValidationResult(ErrorMessage);
            }
        }
        return ValidationResult.Success;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context) {
        ModelClientValidationRule modelClientValidationRule = new ModelClientValidationRule {
            ErrorMessage = FormatErrorMessage(metadata.DisplayName),
            ValidationType = "requiredifattribute"
        };
        modelClientValidationRule.ValidationParameters.Add("dependent", DependentProperty);
        yield return modelClientValidationRule;
    }
}

UPDATE: What I have simply isn't working

Here is how a property in my model is anotated with the above attribute

    [RequiredIf("isFlagSet", true)]
    [Remote("ValidateHosFin", "EditEncounter", AdditionalFields = "hospitalFin, encflag", ErrorMessage = "Got Damn this is complex!")]
    [MinLength(6)]
    public string HostpitalFinNumber { get; set; }

The value in my view that I was trying to key this validation on is set up like so...

   ViewData["ADDENCOREDITTEMP"] = encflag;
   if (encflag == "AddEnc"){
       isFlagSet = true;
   }

I embed it into my page like so...

@Html.Hidden("isFlagSet", isFlagSet, new { id = "isFlagSet"}) 

I can't get my form to submit... The person who said he just tried this and got it to work, could you post the code?

SoftwareSavant
  • 9,467
  • 27
  • 121
  • 195
  • 1
    what exactly is the question? – Necros Oct 16 '12 at 15:15
  • If you want to know how the Data Annotation model validation works look into the source code there is no much documentation available – VJAI Oct 16 '12 at 15:35
  • Well I guess I tried writing my own and so far I haven't got it to work just yet. I obviously am missing some of the finer points and I am trying get a better grip on what to do. I know what I want to do, but I having a hard time getting from A to B so to speak. – SoftwareSavant Oct 16 '12 at 16:00
  • Just tested your code, and it works as intended. Only mistake you have is `$validator` instead of `$.validator`. I'm still not clear on what the actual point of this question is. – Necros Oct 16 '12 at 18:02
  • I can't get my form to submit... I would like to be able to debug this thing, but I am not sure where to begin. – SoftwareSavant Oct 16 '12 at 18:22

1 Answers1

0

Model:

public class X
{
    [RequiredIf("y", "y", ErrorMessage = "y is not y")]
    public string x { get; set; }

    public string y { get; set; }
}

View:

@using(Html.BeginForm())
{
    @Html.ValidationSummary()

    @Html.TextBoxFor(m => m.x)
    @Html.TextBoxFor(m => m.y)

    <input type="submit"/>
}

I assume your validation fails on the server side? do you have isFlagSet property in your view model?

Necros
  • 3,004
  • 23
  • 29
  • I don't set it in my view model. I suppose I could before I navigate to the view. How is your required if working like that? Also, I don't want an error message if the value isn't set. I just don't want the remote function to fire. – SoftwareSavant Oct 16 '12 at 19:01
  • I wish I could find some way to figure out why my form won't submit... I know it has something to do with the attribute, because If I get rid of it, it will actually submit. – SoftwareSavant Oct 16 '12 at 19:05
  • You have to have property with the same name as the `DependentProperty` on your view model in order for it to pass validation on the server, because if it's not there, you don't have anything to validate against. Just put a breakpoint in the `IsValid` method and see that variable `field` is null. – Necros Oct 16 '12 at 19:49
  • Other option would be to just `return ValidationResult.Success;` in the `IsValid` method, and just have the attribute work at client side. But it sounds like what you really need is either a custom `RemoteAttribute` or to handle the validation with custom jQuery code, because this is starting to get a little complex for a generic solution. – Necros Oct 16 '12 at 19:54
  • ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ YES!!!!! I WOULD LOVE TO DO THAT? HOW CAN YOU DO THAT WITH MVC 4 AND UNOBTRUSIVE AJAX... Because I use unobtrusive ajax to open forms for Ajax submits. It wasn't working with the old fashion Html.BeginForm() And @Necros, I will set the breakpoint and check it out. But that is part of the problem, I am pretty clueless as to what is actually happening with the code. And that is no good when you need to customize. – SoftwareSavant Oct 17 '12 at 12:23