0

I am attempting to use a custom validation attribute to ensure a checkbox ends up checked. However, the validation error is displaying (not styled) as part of the checkbox's label prior to the validation firing.

To detail:

I have the following property and attribute:

[Display(Name = "TermsAndConditions", ResourceType = typeof(Res.Labels))]
[MustBeTrue(ErrorMessageResourceName = "TermsAndConditionsValidationMessage", ErrorMessageResourceType = typeof(Res.Labels))]
public bool TermsAndConditions { get; set; } = true;

(for whatever reasons. defaulting to true is deliberate. It's swapped back to false on the view):

@model MyModel
@{ 
        MyModel.TermsAndConditions = false;
}

The custom attribute looks like this:

public class MustBeTrueAttribute : ValidationAttribute, IClientValidatable
    {
        public override bool IsValid(object value)
        {
            return value is bool && (bool)value;
        }

        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            yield return new ModelClientValidationRule
            {       
                ErrorMessage = FormatErrorMessage(Labels.TermsAndConditions),
                ValidationType = "mustbetrue"
            };
        }
    }

The HTML in the view looks like this:

<div class="checkbox">
    @Html.CheckBoxFor(m => m.TermsAndConditions, true)
    <div class="state">
        <label for="terms">
            @Html.Raw(Label.TermsAndConditions)
            @Html.ValidationMessageFor(m => m.TermsAndConditions, Label.TermsAndConditionsValidationMessage)
        </label>
    </div>
</div>

HTML.Raw is used as I need the label to render an anchor element, I couldn't find another way to do it.

The generated HTML on page load is this:

<div class="checkbox">

    <input data-msg-mustbetrue="You must accept the terms and conditions" data-msg-required="The I aceept the <a href=&quot;#&quot;>terms and conditions</a>. field is required." data-rule-mustbetrue="true" data-rule-required="true" id="TermsAndConditions" name="TermsAndConditions" type="checkbox" value="true">
    <input name="TermsAndConditions" type="hidden" value="false">
    <div class="state">
        <label for="terms">
            I aceept the <a href="#">terms and conditions</a>.
            <span class="field-validation-valid" data-valmsg-for="TermsAndConditions" data-valmsg-replace="false">You must accept the terms and conditions</span>
        </label>
    </div>
</div>

termsAndConditionsPreValidation

After firing the validation, everything works as expected:

<div class="checkbox">
    <input data-msg-mustbetrue="You must accept the terms and conditions" data-msg-required="The I aceept the <a href=&quot;#&quot;>terms and conditions</a>. field is required." data-rule-mustbetrue="true" data-rule-required="true" id="TermsAndConditions" name="TermsAndConditions" type="checkbox" value="true" class="input-validation-error">
    <input name="TermsAndConditions" type="hidden" value="false">
    <div class="state">
        <label for="terms">
            I aceept the <a href="#">terms and conditions</a>.
            <span class="field-validation-error" data-valmsg-for="TermsAndConditions" data-valmsg-replace="false">You must accept the terms and conditions</span>
        </label>
    </div>
</div>

termsAndCondtionsAfterValidation

I've been banging my head against the wall on and off with this stuff for a while now, can anyone point me in the right direction? Please and thanks.

3
  • you can set: [DefaultValue(false)] on the property to set the default value to avoid setting it false in view. Commented Mar 19, 2019 at 9:05
  • or remove =true from TermsAndConditions { get; set; } = true Commented Mar 19, 2019 at 9:11
  • Thanks @NomiAli, the ViewModel is used prior to the user actually seeing the view so Page.IsValid returns false unless it's set to true, hence why it's done the way I'm doing it. Commented Mar 19, 2019 at 9:20

1 Answer 1

1

I have finally worked this out after banging my head against the wall.

This particular instance is due to missing CSS. It's normal the error is on the page, it should just be hidden to begin with. This is the only place a custom attribute is being used so it never occurred to me it'd be the CSS as all other validation is on point.

span.field-validation-valid {
        display: none;
}

and voila, sorted.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.