ASP.NET MVC 3 unobtrusive validation and radio buttons
Asked Answered
J

3

11

I'm trying to do required validation on a list of radio buttons to force the user to select an option to continue. The validation does work but it only outputs metadata on the first radio button and it only marks the first radio button with the class input-validation-error.

Example:

<p>@Html.RadioButtonFor(x => x.Choices, SomeEnum.OptionOne)</p>
<p>@Html.RadioButtonFor(x => x.Choices, SomeEnum.OptionTwo)</p>

Resulting HTML:

<p><input class="input-validation-error" data-val="true" data-val-required="required text" type="radio" name="Choices" value="OptionOne" /></p>
<p><input type="radio" name="Choices" value="OptionTwo" /></p>

I want both radio buttons to get the validation error-class or it might risk skewing what option the user selects.

What can I do?

Jilleen answered 14/4, 2011 at 12:55 Comment(1)
How does your view look like? Do you have a @Html.ValidationMessageFor(x => x.Choices)?Santanasantayana
P
7

Please note that the expected behavior of the following code

@Html.RadioButtonFor(x => x.MyEnumProperty, MyEnum.OptionOne)
@Html.RadioButtonFor(x => x.MyEnumProperty, MyEnum.OptionTwo)
@Html.RadioButtonFor(x => x.MyEnumProperty, MyEnum.OptionThree)

is

<input id="MyEnumeration" type="radio" value="Option1" 
       name="MyEnumeration" 
       data-val-required="The MyEnumeration field is required." data-val="true">
<input id="MyEnumeration" type="radio" value="Option2" name="MyEnumeration">
<input id="MyEnumeration" type="radio" value="Option3" name="MyEnumeration">

Why? because Html.SomethingFor(model => model.Property) is meant to generate one html element for one particular property. The way you use it to create more than one element from one property is not correct.

Furthermore, look at the IDs of these 3 radio buttons. They are pretty the same, nah? Is it acceptable to have elements with the same IDs on a html page? Absolutely not! Therefore something needs to be fixed.

Although I thought solving this problem is easier by developing a new Html Extension Methods (reference 2), I tried to solve it in another way (because I'm so stubborn!).

First, We need to change the razor code:

<div>
    @Html.RadioButtonFor(m => m.MyEnumeration, MyEnum.Option1, new { id = "m1" })
    <label for="m1">
        OPTION 1</label>
    @Html.RadioButtonFor(m => m.MyEnumeration, MyEnum.Option2, new { id = "m2" })
    <label for="m2">
        OPTION 2</label>
    @Html.RadioButtonFor(m => m.MyEnumeration, MyEnum.Option3, new { id = "m3" })
    <label for="m3">
        OPTION 3</label>
</div>

Then, a piece of JavaScript/jQuery magic to fix our issue:

<script type="text/javascript">
    $(function () {
        $('[name=MyEnumeration]').each(function (index) { domAttrModified(this); });
    });

    function domAttrModified(obj) {
        //$obj = $(obj);
        $(obj).bind('DOMAttrModified', function () {
            if ($(obj).attr('class').indexOf('input-validation-error') != -1)
                $(obj).parent().addClass('input-validation-error');
            else
                $(obj).parent().removeClass('input-validation-error');
        });
    }
</script>

Anytime the first radio button raises a validation error, this JavaScript code applies error css class (input-validation-error) to the parent element of radio buttons, which is a <div> element.

And anytime validation error goes away (by clicking on any of the radio button elements), error style is removed from the parent element.

It works great in IE and FF, but unfortunately doesn't work in Chrome. The reason is Chrome doesn't support DOMAttrModified event. We can fix it by using this solution: https://mcmap.net/q/412087/-is-there-an-alternative-to-domattrmodified-that-will-work-in-webkit , but maybe sometime later.

Again, I believe we need to develop an HTML Extension Method or improve and use an EditorTemplate like this: https://gist.github.com/973482

References:

  1. https://mcmap.net/q/153186/-how-do-i-use-html-editorfor-to-render-radio-buttons-in-mvc3
  2. https://mcmap.net/q/616794/-how-to-make-a-default-editor-template-for-enums
  3. https://gist.github.com/973482
  4. Event detect when css property changed using Jquery
Poco answered 29/6, 2012 at 21:38 Comment(0)
S
4

This can be performed by using the showErrors callback:

$("form").data("validator").settings.showErrors = function (errorMap, errorList) {
    this.defaultShowErrors();

    $("input[type=radio][data-val=true].input-validation-error").each(function () {
        $("input[name=" + $(this).attr('name') + "]").addClass("input-validation-error");
    });

    $("input[type=radio][data-val=true]:not(.input-validation-error)").each(function () {
        $("input[name=" + $(this).attr('name') + "]").removeClass("input-validation-error");
    });
};
Shapely answered 16/7, 2012 at 21:50 Comment(1)
Unfortunately this results in the client side validation not blocking the POST any more. Any ideas why?Escribe
T
-1

What i did was to disabled the css for the radiobutton and only show the error message. (not sure IE likes this)

.input-validation-error input[type="radio"]
{
    border: 0x solid #ff0000;
    background-color: inherit;
}
Tychon answered 10/8, 2011 at 18:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.