client-side validation in custom validation attribute - asp.net mvc 4

Posted by Giorgos Manoltzas on Stack Overflow See other posts from Stack Overflow or by Giorgos Manoltzas
Published on 2013-11-01T12:04:25Z Indexed on 2013/11/01 15:54 UTC
Read the original article Hit count: 251

I have followed some articles and tutorials over the internet in order to create a custom validation attribute that also supports client-side validation in an asp.net mvc 4 website. This is what i have until now:

RequiredIfAttribute.cs

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)] //Added
public class RequiredIfAttribute : ValidationAttribute, IClientValidatable
{
    private readonly string condition;
    private string propertyName; //Added

    public RequiredIfAttribute(string condition)
    {
        this.condition = condition;
        this.propertyName = propertyName; //Added
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        PropertyInfo propertyInfo = validationContext.ObjectType.GetProperty(this.propertyName); //Added
        Delegate conditionFunction = CreateExpression(validationContext.ObjectType, _condition);
        bool conditionMet = (bool)conditionFunction.DynamicInvoke(validationContext.ObjectInstance);

        if (conditionMet)
        {
            if (value == null)
            {
                return new ValidationResult(FormatErrorMessage(null));
            }
        }

        return ValidationResult.Success;
    }

    private Delegate CreateExpression(Type objectType, string expression)
    {
        LambdaExpression lambdaExpression = System.Linq.Dynamic.DynamicExpression.ParseLambda(objectType, typeof(bool), expression); //Added
        Delegate function = lambdaExpression.Compile();
        return function;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var modelClientValidationRule = new ModelClientValidationRule
        {
            ValidationType = "requiredif",
            ErrorMessage = ErrorMessage //Added
        };

        modelClientValidationRule.ValidationParameters.Add("param", this.propertyName); //Added
        return new List<ModelClientValidationRule> { modelClientValidationRule };
    }
}

Then i applied this attribute in a property of a class like this

[RequiredIf("InAppPurchase == true", "InAppPurchase", ErrorMessage = "Please enter an in app purchase promotional price")] //Added "InAppPurchase"
public string InAppPurchasePromotionalPrice { get; set; }

public bool InAppPurchase { get; set; }

So what i want to do is display an error message that field InAppPurchasePromotionalPrice is required when InAppPurchase field is true (that means checked in the form). The following is the relevant code form the view:

<div class="control-group">
                <label class="control-label" for="InAppPurchase">Does your app include In App Purchase?</label>
                <div class="controls">
                    @Html.CheckBoxFor(o => o.InAppPurchase)
                    @Html.LabelFor(o => o.InAppPurchase, "Yes")
                </div>
            </div>
            <div class="control-group" id="InAppPurchasePromotionalPriceDiv" @(Model.InAppPurchase == true ? Html.Raw("style='display: block;'") : Html.Raw("style='display: none;'"))>
                <label class="control-label" for="InAppPurchasePromotionalPrice">App Friday Promotional Price for In App Purchase: </label>
                <div class="controls">
                    @Html.TextBoxFor(o => o.InAppPurchasePromotionalPrice, new { title = "This should be at the lowest price tier of free or $.99, just for your App Friday date." })
                    <span class="help-inline">
                        @Html.ValidationMessageFor(o => o.InAppPurchasePromotionalPrice)
                    </span>
                </div>
            </div>

This code works perfectly but when i submit the form a full post is requested on the server in order to display the message. So i created JavaScript code to enable client-side validation:

requiredif.js

(function ($) {
    $.validator.addMethod('requiredif', function (value, element, params) {
        /*var inAppPurchase = $('#InAppPurchase').is(':checked');

        if (inAppPurchase) {
            return true;
        }

        return false;*/

        var isChecked = $(param).is(':checked');

        if (isChecked) {
            return false;
        }

        return true;
    }, '');

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

This is the proposed way in msdn and tutorials i have found

Of course i have also inserted the needed scripts in the form:

  1. jquery.unobtrusive-ajax.min.js
  2. jquery.validate.min.js
  3. jquery.validate.unobtrusive.min.js
  4. requiredif.js

BUT...client side validation still does not work. So could you please help me find what am i missing? Thanks in advance.

© Stack Overflow or respective owner

Related posts about c#

Related posts about jQuery