Jake
Jake

Reputation: 165

Client-Side Custom Unobtrusive Validation Not Working

Using MVC4, I have created a custom Validation Attribute that implements the IClientValidatable Interface as shown below:

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        ModelClientValidationRule rule = new ModelClientValidationRule();
        rule.ErrorMessage = ErrorMessages.ClientFieldInputValidation;
        rule.ValidationType = "regularexpression";
        rule.ValidationParameters.Add("pattern", _regEx);
        yield return rule;
    }

I have also implemented the 'regularexpression' client script as shown below:

(function($) {
    $.validator.addMethod('regularexpression', function(value, element, params) {
        var regEx = RegExp(params['pattern']);
        return regEx.test($(element).val());
    });

    $.validator.unobtrusive.adapters.addBool('regularexpression');

})(jQuery)

The issue I have is that the Regular Expression is not getting picked up in the 3rd line of the JavaScript: var regEx = RegExp(params['pattern']);. Thus the client-side validation is not working correctly. The server side validation is working fine as when I hit Submit, it returns back with the correct feedback.

Note: I have also tried hard-coding the regular expression in replacement of params['pattern'] and it works fine.

Could anyone help me with this as my knowledge on JavaScript is not what you would call strong.

Upvotes: 3

Views: 3560

Answers (2)

HyoukJoon Lee
HyoukJoon Lee

Reputation: 171

If you want to apply multiple regular expression validation on one data object along with the client validation, You cannot use same ValidationType name as "regex". You need to use your own custom unique ValidationType somehow. The problem of your javascript part is that you are using wrong injection method for your regular expression validator method.

$.validator.unobtrusive.adapters.addBool('regularexpression');

you need to use below method instead of above in order to pass your server-side pattern value into the client-side method

$.validator.unobtrusive.adapters.addSingleVal("regularexpression", "pattern");

Here is my sample source...

On server side, create each custom validation attributes.

public class OneDigitAttribute : RegularExpressionAttribute, IClientValidatable
{
    public OneDigitAttribute()
        : base(@"^.*(?=.*\d).+$")
    {
        ErrorMessage = "Required at least one numeric digit";
    }

    // for supporting a client-side validation through jquery.validation.unobtrusive
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        yield return new ModelClientValidationRegexRule(this.ErrorMessage, this.Pattern)
        {
            ValidationType = "onedigit"
        };
    }
}

public class OneAlphaAttribute : RegularExpressionAttribute, IClientValidatable
{
    public OneAlphaAttribute()
        : base(@"^.*(?=.*[a-zA-Z]).+$")
    {
        ErrorMessage = "Required at least one alphabet character";
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        yield return new ModelClientValidationRegexRule(this.ErrorMessage, this.Pattern)
        {
            ValidationType = "onealpha"
        };
    }
}

public class OneSpecialCharacterAttribute : RegularExpressionAttribute, IClientValidatable
{
    public OneSpecialCharacterAttribute()
        : base(@"^.*(?=.*[^a-zA-Z0-9]).+$")
    {
        ErrorMessage = "Required at least one non alphabet numeric(special) character";
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        yield return new ModelClientValidationRegexRule(this.ErrorMessage, this.Pattern)
        {
            ValidationType = "onespecial"
        };
    }
}

and apply them on same property

[OneDigit]
[OneAlpha]
[OneSpecialCharacter]
[DataType(DataType.Password)]
public string NewPassword { get; set; } 
...

and then, add each unique validation method on client side as below

$.validator.addMethod("onedigit", function (value, element, regexp) {
    var re = new RegExp(regexp); return re.test(value);
});

$.validator.addMethod("onealpha", function (value, element, regexp) {
    var re = new RegExp(regexp); return re.test(value);
});
$.validator.addMethod("onespecial", function (value, element, regexp) {
    var re = new RegExp(regexp); return re.test(value);
});
jQuery.validator.unobtrusive.adapters.addSingleVal("onedigit", "pattern");
jQuery.validator.unobtrusive.adapters.addSingleVal('onealpha', "pattern");
jQuery.validator.unobtrusive.adapters.addSingleVal('onespecial', "pattern");

and please make sure not put them all inside of DOM ready function. For example:

/* $(function() { */
$.validator.addMethod("regularexpression", function (value, element, regexp) {
    var re = new RegExp(regexp); return re.test(value);
});
$.validator.unobtrusive.adapters.addSingleVal("regularexpression", "pattern");
/* }); */

Upvotes: 11

Nick
Nick

Reputation: 1122

Try changing the validation type so that it matches the inbuilt RegEx validator. When the html is generated, the existing RegEx logic fires, so you wont need to write any javascript.

public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
    ModelClientValidationRule rule = new ModelClientValidationRule();
    rule.ErrorMessage = ErrorMessages.ClientFieldInputValidation;
    rule.ValidationType = "regex";
    rule.ValidationParameters.Add("pattern", _regEx);
    yield return rule;
}

Upvotes: 0

Related Questions