Search code examples
jqueryasp.net-mvc-5jquery-validatedata-annotationsunobtrusive-validation

Custom data annotation validation on Client Site : $.validator.addMethod error


From this answer I have write my code from this blog DevTrends for performing custom data annotation validation. But in client site in $.validator.addMethod( ) method getting the error in the bellowed image. Please help me to come out from this problem.

message  :"value is not defined"
stack  : "ReferenceError: value is not defined↵    at eval (eval at <anonymous> (http://localhost:61052/boatproduction/edit/2?pg=1&sz=10&st=id&dr=desc:71:13), <anonymous>:1:1)↵    at http://localhost:61052/boatproduction/edit/2?pg=1&sz=10&st=id&dr=desc:1279:13↵    at http://localhost:61052/boatproduction/edit/2?pg=1&sz=10&st=id&dr=desc:1288:10" 

enter image description here

My View model is like below

   public class BoatProductionModel
{
    public long Id { get; set; } 
    public DateTime StartDate { get; set; }        
    [DateComparison("StartDate")]
    public DateTime LastUpdate { get; set; }       
    public int? NumberOfEmployee { get; set; }        
}


[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public sealed class DateComparison : ValidationAttribute
{
    private const string DefaultErrorMessage = "{0} cannot be the same as {1}.";
    public string OtherProperty { get; private set; }

    public DateComparison(string otherProperty)
      : base(DefaultErrorMessage)
    {
        if (string.IsNullOrEmpty(otherProperty))
        {
            throw new ArgumentNullException("otherProperty");
        }

        OtherProperty = otherProperty;
    }

    public override string FormatErrorMessage(string name)
    {
        return string.Format(ErrorMessageString, name, OtherProperty);
    }

    protected override ValidationResult IsValid(object value,
                          ValidationContext validationContext)
    {
        if (value != null)
        {
            var otherProperty = validationContext.ObjectInstance.GetType()
                               .GetProperty(OtherProperty);

            var otherPropertyValue = otherProperty
                          .GetValue(validationContext.ObjectInstance, null);

            if (value.Equals(otherPropertyValue))
            {
                return new ValidationResult(
                  FormatErrorMessage(validationContext.DisplayName));
            }
        }
        return null;  //return ValidationResult.Success;
    }

    public IEnumerable<ModelClientValidationRule> 
GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var clientValidationRule = new ModelClientValidationRule()
        {
            ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
            ValidationType = "notequalto"
        };

        clientValidationRule.ValidationParameters.Add("otherproperty", OtherProperty);

        return new[] { clientValidationRule };
    }
}

Here is the code I used in View :

Razor Code :

 @model  Data.AppModels.BoatProductionModel
 @Html.TextBoxFor(model => model.LastUpdate, "{0:MM/dd/yyyy}", new { @class = "form-control pull-right", placeholder = "Last Update"    })
 @Html.ValidationMessageFor(model => model.LastUpdate)

JavaScript Code:

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

        }(jQuery));

Solution

  • Your custom attribute does not implement IClientValidatable (although your have included the GetClientValidationRules() method defined in that interface. As a result the data-val-* attributes associated with your attribute are not generated in the html and therefore jquery.validate.unobtrusive.js does not add the rules to jquery.validate.js

    Change the signature of your validation attribute to

    public sealed class DateComparison : ValidationAttribute, IClientValidatable
    {
        ....
    }
    

    and the html for your input will now include the following attributes

    data-val-notequalto="LastUpdate cannot be the same as StartDate." data-val-notequalto-otherproperty="StartDate"
    

    that will be parsed by jquery.validate.unobtrusive.js.

    Note also that you do not need to wrap the scripts in (function ($) {