Nolonar
Nolonar

Reputation: 6122

Validation is only applied to the first item of an array

Given this model code

[Required]
[Display(Name = "Name")]
public string Name { get; set; }

the following view code works

@Html.LabelFor(model => model.Name)
@Html.TextBoxFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)

Whenever I leave the Name field empty, the TextBox is highlighted in red, and a "The Name field is required." error message appears, which is good.


However, my model also contains an Option[] Options which also need to be validated.

Given this model code

private const string orderNoDisplayName = "Order number";
[Required]
[RegularExpression(@"\d+",
              ErrorMessage = "The " + orderNoDisplayName  + " field must be numeric.")]
[Display(Name = orderNoDisplayName )]
public string OrderNo { get; set; }

the following view code doesn't quite work as expected

@foreach (var option in Option.GetDefaultOptions())
{
    <li>
        @Html.TextBoxFor(model => option.OrderNo, new { id = option.IdString })
        @Html.ValidationMessageFor(model => option.OrderNo,
                                       null, new { data_valmsg_for = option.IdString })
    </li>
}

The very first option works perfectly, but any subsequent option doesn't.

Below is the automatically generated code for 2 options

<ul>

    <li> <!-- automatically generated code for 'option_1' -->
        <input data-val="true" data-val-regex="The Order number field must be numeric."
data-val-regex-pattern="\d+" data-val-required="The Order number field is required."
id="option_1" name="OrderNo" type="text" value="0" class="input-validation-error">

        <span class="field-validation-valid" data-valmsg-for="option_1"
data-valmsg-replace="true"></span>
    </li>

    <li> <!-- automatically generated code for 'option_2' -->
        <input id="option_2" name="OrderNo" type="text" value="0"
class="input-validation-error">

        <span class="field-validation-valid" data-valmsg-for="option_2"
data-valmsg-replace="true"></span>
    </li>

</ul>

So obviously, MVC did not add any validation attributes to my second option or any subsequent options at all.

Of course, I could hardcode the validations into a handwritten <input> tag, but I'd like to avoid doing so. What can I do to make the validation work for all options, instead of only the first one?

Upvotes: 2

Views: 2186

Answers (1)

hutchonoid
hutchonoid

Reputation: 33306

I think the problem is the for loop, as the model binder is not indexing the name field they're coming out identical and it looks like there is only one i.e. name="OrderNo".

Try changing your loop to index it as follows:

@for (var i = 0; i < Option.GetDefaultOptions().Count; i++)
{
    <li>
        @Html.TextBoxFor(model => Option.GetDefaultOptions()[i].OrderNo, new { id = Option.GetDefaultOptions()[i].IdString })
        @Html.ValidationMessageFor(model => Option.GetDefaultOptions()[i].OrderNo,
                                       null, new { data_valmsg_for = Option.GetDefaultOptions()[i].OrderNo.IdString })
    </li>
}

You should then see that they're written out as follows:

 name="[0].OrderNo"
 name="[1].OrderNo"

Upvotes: 4

Related Questions