Styling jQuery Validation with Select2 4.0 and Bootstrap 3+

18.1k views Asked by At

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/

5

There are 5 answers

1
Sparky On BEST ANSWER

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/

0
Yasin Patel On

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);
  }
}
0
adamj On

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);
}
0
Valentin R. On

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.

2
Fr0zenFyr On

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.