Styling jQuery Validation with Select2 4.0 and Bootstrap 3+
Asked Answered
E

5

12

I have a project that uses Bootstrap 3.3.4, Select2 4.0, and Jquery Validation 1.13.1

I have set the jquery validator defaults to style bootstrap 3 classes like so

 $.validator.setDefaults({
    errorElement: "span",
    errorClass: "help-block",

    highlight: function (element, errorClass, validClass) {
    $(element).addClass(errorClass);
        $(element).closest('.form-group').removeClass('has-success').addClass('has-error');
    },
    unhighlight: function (element, errorClass, validClass) {
    $(element).removeClass(errorClass);
        $(element).closest('.form-group').removeClass('has-error').addClass('has-success');
    },

    errorPlacement: function(error, element) {
        if(element.parent('.input-group').length) {
           error.insertAfter(element.parent());
        } else {
            error.insertAfter(element);
        }

    }
});

But these defaults do not style select2 fields the same... in the image below, the "metals" select is a bootstrap field, while the "colors" select is a select2 field.

enter image description here

I tried searching other SO's , but all of these use the 3.5.xx version of select2

I included a jsfiddle of the example pictured, I am looking for adjustments to the validator defaults to have select2 look uniform

http://jsfiddle.net/z49mb6wr/

Ezaria answered 11/6, 2015 at 14:1 Comment(2)
Select2 has a Bootstrap theme you can use.T
Thank you @KevinBrown , i did implement that as well as altering the jquery validate defaults, works great nowEzaria
S
26

I tried searching other SO's, but all of these use the 3.5.xx version of select2

There is no secret formula for various versions; you just have to figure it out for your situation. That means you need to inspect the rendered DOM so you know which elements to target and how to target them.

I don't claim that the code below will work for you; it's just an example how to attack this situation.

  1. Write CSS that targets the rendered Select2 element. So whenever the parent container has the class has-error, the Select2 element will be styled as such.

    .has-error .select2-selection {
        border: 1px solid #a94442;
        border-radius: 4px;
    }
    
  2. To get the error message to display after the Select2 element simply requires another conditional within the errorPlacement option along with some jQuery DOM traversal.

    errorPlacement: function (error, element) {
        if (element.parent('.input-group').length) { 
            error.insertAfter(element.parent());      // radio/checkbox?
        } else if (element.hasClass('select2')) {     
            error.insertAfter(element.next('span'));  // select2
        } else {                                      
            error.insertAfter(element);               // default
        }
    }
    
  3. And finally, since interacting with the Select2 does not have any events that the jQuery Validate plugin automatically captures, you will have to write a custom event handler and programmatically trigger validation.

    $('.select2').on('change', function() {
        $(this).valid();
    });
    

Working DEMO: http://jsfiddle.net/z49mb6wr/1/

Superimpose answered 11/6, 2015 at 15:37 Comment(1)
for another case or newer version this will works if (element.hasClass("select2-hidden-accessible")) { error.insertAfter(element.next('span.select2')); }Suppurate
J
3

A small modification to @Sparky's solution - I don't take the credit except for figuring out that error and valid classes are used by latest jquery validate(:P) as on date:

/*! jQuery Validation Plugin - v1.16.0 - 12/2/2016
 * http://jqueryvalidation.org/
 * Copyright (c) 2016 Jörn Zaefferer; Licensed MIT */

Now code:

$('#MyForm').validate({
    errorPlacement: function (error, element) {
        if (element.parent('.input-group').length) { 
            error.insertAfter(element.parent());      // radio/checkbox?
        } else if (element.hasClass('select2-hidden-accessible')) {     
            error.insertAfter(element.next('span'));  // select2
            element.next('span').addClass('error').removeClass('valid');
        } else {                                      
            error.insertAfter(element);               // default
        }
    }
});

// add valid and remove error classes on select2 element if valid
$('.select2-hidden-accessible').on('change', function() {
    if($(this).valid()) {
        $(this).next('span').removeClass('error').addClass('valid');
    }
});

Use CSS on error class as it pleases you.

Jimmie answered 1/4, 2017 at 6:53 Comment(2)
ok ill take a look at this, as radios are not working in the original answerEzaria
@JayRizzi if you can include a sample of your HTML for radios, it will be easier to see why it doesn't work for you.Jimmie
A
2

Sparky's answer just didn't work for me, so I modified it to the below:

if (element.hasClass('select2-hidden-accessible')) {
    error.insertAfter(element.closest('.has-error').find('.select2'));
} else if (element.parent('.input-group').length) { 
    error.insertAfter(element.parent());
} else {                                      
    error.insertAfter(element);
}
Anteater answered 2/12, 2016 at 1:6 Comment(0)
W
0

Give class to your select2 element And use that class in errorPlacement.

For example in below dropdown i have give select2_custom_class class for select2 element

<select type="text" id="test1" class="form-control select2_custom_class">
    <option value="">Select</option>
</select>

And use that class in errorPlacement

errorPlacement: function (error, element) {
  if(element.hasClass('select2_custom_class')) {
    error.insertAfter(element.next('.select2-container'));
    // OR
    error.insertAfter(element.next('span'));
  }
  else {
    error.insertAfter(element);
  }
}
Webbing answered 9/7, 2021 at 5:41 Comment(0)
C
0

Trid all the solutions proposed here on 4.1 RC0, none seems to work. Since I do use Jquery (and is mandatory), here is my solution: I put after the a div that has a class named "error-insert-after", and in errorPlacement, I have :

errorPlacement: function (error, element) {
            // Add the `invalid-feedback` class to the error element
            error.addClass("invalid-feedback");
            if (element.prop("type") === "checkbox") {
                error.insertAfter(element.next("label"));
            } else {
                error.insertAfter(element);
            }
            if (element.hasClass('select2-hidden-accessible')) {
                error.insertAfter($('.error-insert-after'));
            } else if (element.parent('.input-group').length) {
                error.insertAfter(element.parent());
            } else if (element.prop('type') === 'radio' && element.parent('.radio-inline').length) {
                error.insertAfter(element.parent().parent());
            } else if (element.prop('type') === 'checkbox' || element.prop('type') === 'radio') {
                error.appendTo(element.parent().parent());
            } else {
                error.insertAfter(element);
            }

Since I only have one field to validate, it enough for me. For some reason, next don't work, it may be my setup, but, if it helps someone, your welcome.

Cargile answered 15/11, 2021 at 12:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.