How to correctly override "jQuery Unobtrusive Validation" to work for css bootstrap?
Asked Answered
D

1

8

I have an ASP.NET MVC 5 base project in which I use css bootstrap for designing my pages.

To work property with css bootstrap. I want to be able to override the default behavior of the errorElement, errorClass, highlight,unhighlight and errorPlacement properties/functions.

This is what I have tried

First, I included the packages in the following order

  1. jQuery (v3.1.1)
  2. jquery.validate.min.js (v1.15.0)
  3. My settings where I override the default behavior (Code below)
  4. jquery.validate.unobtrusive.js (v3.2.3)

This is my first attempt into overriding the package

$.validator.setDefaults({
    errorElement: "span",
    errorClass: "help-block",
    highlight: function (element, errorClass, validClass) {
        $(element).closest('.form-group').addClass('has-error');
    },
    unhighlight: function (element, errorClass, validClass) {
        $(element).closest('.form-group').removeClass('has-error');
    },
    errorPlacement: function (error, element) {

        var elm = $(element);

        console.log('errorPlacement was called');

        if (elm.parent('.input-group').length) {
            console.log('parent');
            console.log(elm.parent());
            error.insertAfter(elm.parent());
        }
        else if (elm.prop('type') === 'checkbox' || elm.prop('type') === 'radio') {
            error.appendTo(elm.closest(':not(input, label, .checkbox, .radio)').first());
        } else {
            error.insertAfter(elm);
        }
    }
});

However, the above code will never call the errorPlacement function, other than that everything else works as expected. But since the errorPlacement method is not being called, the error is being placed in a different place.

Then I changed the above code to this (overriding both jQuery validation and the Unobtrusive)

$.validator.setDefaults({
    errorElement: "span",
    errorClass: "help-block",
    highlight: function (element, errorClass, validClass) {
        console.log('highlight was called');
        $(element).closest('.form-group').addClass('has-error');
    },
    unhighlight: function (element, errorClass, validClass) {
        console.log('highlight was called');
        $(element).closest('.form-group').removeClass('has-error');
    },
    errorPlacement: function (error, element) { }
});

$.validator.unobtrusive.options = {
    errorPlacement: function (error, element) {

        var elm = $(element);
        console.log('errorPlacement was called');

        if (elm.parent('.input-group').length || elm.parent('.input-group-custom').length) {
            console.log('parent');
            console.log(elm.parent());
            error.insertAfter(elm.parent());
        }
        else if (elm.prop('type') === 'checkbox' || elm.prop('type') === 'radio') {
            error.appendTo(elm.closest(':not(input, label, .checkbox, .radio)').first());
        } else {
            error.insertAfter(elm);
        }
    }
};

Now, the function errorPlacement is being called. But, the error is being inserted multiple time. Somehow the code the removes the error message is not being called now.

How can I fix this issue?

Disparate answered 3/4, 2017 at 16:43 Comment(6)
That didn't work? Did you place $.validator.setDefaults() inside or outside of your document ready function?Bearskin
It did not work. Yes I placed it inside $(function () {....}); block. To make sure I am clear on what did not work is that the function errorPlacement was not called. but the rest worked fine.Disparate
That's your problem. Thanks to the Unobtrusive plugin, your .setDefaults() is being called after the .validate() initialization. The only way to force .setDefaults() to get called before .validate() in this case is to place it outside of your document ready.Bearskin
It's not likely that only some of .setDefaults() is being ignored.Bearskin
is there a workaround?Disparate
Workaround for what? Read previous comment: "The only way to force .setDefaults() to get called before .validate() in this case (with unobtrusive) is to place it (setDefaults) outside of your document ready."Bearskin
G
16

This is how I override jQuery Unobtrusive Validation to work with Bootstrap 4.

$.validator.setDefaults({
    errorClass: "",
    validClass: "",
    highlight: function (element, errorClass, validClass) {
        $(element).addClass("is-invalid").removeClass("is-valid");
        $(element.form).find('[data-valmsg-for="' + element.name + '"]').addClass("invalid-feedback");
    },
    unhighlight: function (element, errorClass, validClass) {
        $(element).addClass("is-valid").removeClass("is-invalid");
        $(element.form).find('[data-valmsg-for="' + element.name + '"]').removeClass("invalid-feedback");
    },
});

Copy and paste the code above into a new file. Name it jquery.validate.overrides.js.

Edit BundleConfig.cs. Find the bundle jqueryval. Add path to new file at the end.

bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
    "~/Scripts/jquery.validate.js",
    "~/Scripts/jquery.validate.unobtrusive.js",
    "~/Scripts/jquery.validate.overrides.js"
));

To use in a view:

<div class="form-group">
    @Html.LabelFor(m => m.FirstName)
    @Html.TextBoxFor(m => m.FirstName, new { @class = "form-control", placeholder = "First name", type = "text" })
    @Html.ValidationMessageFor(m => m.FirstName)
</div>
Glanders answered 3/10, 2019 at 8:58 Comment(2)
This is great. One issue i've found though is that if you get past client validation and server-side validation fails then the page doesn't add the bootstrap classes. Did you find a way to solve that?Pointdevice
I also have the same problem as Dave, only works for client side, server side overrides the class with the standard 'input-validation-error'.Cynthea

© 2022 - 2024 — McMap. All rights reserved.