Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Client-side validation not firing for CompareAttribute DataAnnotation

I'm laying out a view that compares two password strings. The two properties in one of my models are pretty straightforward:

    [Required]
    [RegularExpression(@"(\S)+", ErrorMessage = "White space is not allowed")]
    [StringLength(20, MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "New Password")]
    public string NewPassword { get; set; }

    [Required]
    [DataType(DataType.Password)]
    [RegularExpression(@"(\S)+", ErrorMessage = "White space is not allowed")]
    [StringLength(20, MinimumLength = 6)]
    [Display(Name = "Confirm Password")]
    [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }

Here's my view code:

<table class="fieldset center" width="400">
    <tbody>
        <tr>
            <th width="150">
                @Html.LabelFor(m => m.NewPassword)
            </th>
            <td>
                @Html.PasswordFor(m => m.NewPassword, new { @class = "itext3" })
                <br /><br />@Html.ValidationMessageFor(m => m.NewPassword)
            </td>
        </tr>                       
        <tr>
            <th width="150">
                @Html.LabelFor(m => m.ConfirmPassword)
            </th>
            <td>
                @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "itext3" })
                <br /><br />@Html.ValidationMessageFor(m => m.ConfirmPassword)
            </td>
        </tr>
    </tbody>
</table>

All of the attributes fire their client-side validation messages when tested, except for the CompareAttribute on ConfirmPassword which is not firing until I hit the server. However, in my controller the ModelState.IsValid = false.

I compared what I'm doing to the default MVC application which is working correctly. Any suggestions for troubleshooting and fixing this?

I'm using MVC 3 RTM.

like image 256
beaudetious Avatar asked Jan 14 '11 21:01

beaudetious


1 Answers

There is a BUG in jquery.validate.unobtrusive.js (and jquery.validate.unobtrusive.min.js, the minified version). The client-side validation emitted as a result of the [Compare] attribute will ONLY work if the compare-to field is the FIRST field on the form. To fix this bug, locate this line in jquery.validate.unobtrusive.js:

element = $(options.form).find(":input[name=" + fullOtherName + "]")[0];

which results in this equivalent:

element = $(options.form).find(":input[name=MyExample.Control]")[0];

Unfortunately that's not the right syntax for find(), and causes it to reference the first input control on the form.

Change that line to:

element = $(options.form).find(":input[name='" + fullOtherName + "']")[0];

which results in this equivalent:

element = $(options.form).find(":input[name='MyExample.Control]'")[0];

Which is the correct syntax, and correctly matches the input control with the specified name.

Locate the same code block in jquery.validate.unobtrusive.min.js, which looks like this:

f=a(b.form).find(":input[name="+d+"]")[0];

and change it to:

f=a(b.form).find(":input[name='"+d+"']")[0];
like image 85
Mark Shapiro Avatar answered Oct 11 '22 15:10

Mark Shapiro