Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC DropDownListFor and StringLength Attribute Not Playing Well together

My stringlength validation always fails on dropdownlists with a string value.

Here is my model:

[Required(ErrorMessage = "Required")]
[StringLength(2, MinimumLength = 2)]
[Display(Name = "Home Address State")]
public string HomeAddressState { get; set; }

Here is my view:

@Html.DropDownListFor(model => model.HomeAddressState, new SelectList(ViewBag.States, "Value", "Text"), string.Empty)
@Html.ValidationMessageFor(model => model.HomeAddressState)

Here is the html output:

<select data-val="true" data-val-length="The field Home Address State must be a string with a minimum length of 2 and a maximum length of 2." data-val-length-max="2" data-val-length-min="2" data-val-required="Required" id="HomeAddressState" name="HomeAddressState"><option value=""></option>
<option value="CA">California</option>
<option value="IL">Illinois</option>
<option value="IN">Indiana</option>
<option value="OH">Ohio</option>
</select>

No matter what option is selected, the StringLength validation fails client-side. What am I doing incorrectly?

like image 817
Jason Butera Avatar asked Jul 10 '12 16:07

Jason Butera


2 Answers

Here's the relevant jquery-validation code. As you can see, it looks like it applies the length validation to the number of options selected, not the length of the option. Seems to only apply to multi-select listboxes. Kind of odd, to be honest.

maxlength: function(value, element, param) {
    return this.optional(element) || this.getLength($.trim(value), element) <= param;
}

getLength: function(value, element) {
    switch( element.nodeName.toLowerCase() ) {
        case 'select':
            return $("option:selected", element).length;
        case 'input':
            if( this.checkable( element) )
                return this.findByName(element.name).filter(':checked').length;
    }
    return value.length;
}

What you can do is override the getLength function yourself to just return value.length directly.

$.validator.prototype.getLength = function (value, element) {
    return value.length;
}
like image 166
bhamlin Avatar answered Nov 09 '22 12:11

bhamlin


To avoid breaking the logic for checkboxes and multiple selectboxes, you could use:

$.validator.prototype.getLength = function (value, element) {
    switch (element.nodeName.toLowerCase()) {
        case 'select':
            {
                var attr = $(this).attr('multiple');
                // For some browsers, `attr` is undefined; for others,
                // `attr` is false.  Check for both.
                if (typeof attr !== 'undefined' && attr !== false) {
                    return $("option:selected", element).length;
                }
            }
        case 'input':
            if (this.checkable(element))
                return this.findByName(element.name).filter(':checked').length;
    }
    return value.length;
}

WARNING: I tested this only on DropDownFor, so use at your own risk....

like image 20
JustAMartin Avatar answered Nov 09 '22 14:11

JustAMartin