Force to Show Invalid-Feedback in Bootstrap 4

Force to show invalid-feedback in Bootstrap 4

Use display classes to display it manually for example d-block

use it like so

<div class="valid-feedback d-block"> 

or

<div class="invalid-feedback d-block">

Find more in documentation

Bootstrap 4 invalid feedback with input group not displaying

They haven't taken into account their own examples using input group addons and buttons, even with a column model. The markup does only facilitate "neighboring" elements, not parent > neighboring element (there is no CSS rule for that).

It seems, for now, you should fall back to Alpha 6 or program your own CSS classes accordingly. I've done the same, unfortunately.

Please note when reading my answer that this was posted just as the beta was released. :)

Bootstrap 4.0 invalid-feedback doesn't show

You're right, the intention is that the input is a sibling of the feedback message. The only way you can force the invalid-feeback to show is to use something like d-block (or some custom CSS selector). Perhaps you can add d-block programatically in your app during validation.

<div class="form-row">
<label class="form-control-label">Name:</label>
<div class="col-4">
<input class="form-control is-invalid" min="0" type="number"/>
</div>
<div class="col-4">
<div class="invalid-feedback d-block">
Invalid Feedback Text
</div>
</div>
</div>

Bootstrap 4 form validation not working while Using invalid-feedback even when input 'is-valid'

The reason its not working is that you are not wrapping your label and input in form-group div

Validation has changed the way it used to be for bootstrap - Which means the is-valid and is invalid does not know where to look so when its not in the form-group div wrapped it applies the is-invalid message to all the matching divs.

I have added label to make it nice instead of using just Email: <input>

If you submit the form now without any values it will display the errors _ the error will disappear as soon as you type into the input.

Run Snippet below to see it woking.

/**
* AJAX Post script
*/

const ERROR_TYPE_FATALERROR = 1;
const ERROR_TYPE_INPUTERROR = 2;
const ERROR_TYPE_GLOBALMESSAGE = 3;

// Run through the validate() function ONLY once the form as been submitted once!
// Otherwise, user will get validation right away as he types! Just a visual thing ...
var formSubmittedOnce = false;

/**
* submitFormData()
* Serialize and post form data with an AJAX call
*
* Example: onClick="submitFormData('frm1',['username','email'])"
*
* @param string formid essentially the 'id' of the container holding all form elements (i.e. <tr id="rowfrm_1">, <form id='frm1'>, etc.)
* @param array fields list of field names that may produce input errors (i.e. ['username','email'] )
*/
function submitFormData(formid, fields) {

// flag form was submitted once!
formSubmittedOnce = true;

// ----------------------------------
// first rehide all error containers
// ----------------------------------
$('#fatalError').removeClass('d-block');
$('#fatalErrorID').removeClass('d-block');
$('#fatalErrorTrace').removeClass('d-block');
$('#fatalErrorGoBack').removeClass('d-block');

$('#globalMessage').removeClass('d-block');
$('#globalMessageID').removeClass('d-block');
$('#globalMessageTrace').removeClass('d-block');
$('#globalMessageFooter').removeClass('d-block');
$('#globalMessageMailLink').removeClass('d-block');
$('#globalMessageGoBackLink').removeClass('d-block');

// rehide error containers of all inputs that might produce errors
if (fields != null) {
for (const f of fields) {
$('#' + f + '_inputError').removeClass('d-block');
}
}

// ----------------------------------
// loop form elements and validate required fields
// ----------------------------------
var formNode = $("#" + formid);
var formInputs = formNode.find("select, textarea, input");
var submit = true;

for (var i = 0; i < formInputs.length; ++i) {
var input = formInputs[i];

// validate fields
if (validate(input) === false) {
submit = false;
}
}

if (submit === true) {

// ----------------------------------
// get form data and serialize it!
// ----------------------------------

// formid comes from a <form>. just serialize it
if (formNode.prop("tagName") === "FORM") {
var formData = formNode.serialize();
}
// formid doesn't come from a <form>
else {

// get all form control
var myInputs = formNode.clone();

// bug with clone() and SELECT controls: it'll only get the value of the option having the 'selected' attribute (the default value)
// this hack will change the value clone() got to the actual user selected value, and not the default set value!
formNode.find('select').each(function(i) {
myInputs.find('select').eq(i).val($(this).val());
})

// create a dummy form, append all inputs to it and serialize it.
var formData = $('<form>').append(myInputs).serialize();
}

// ----------------------------------
// POST !
// ----------------------------------
$.ajax({
type: 'POST',
url: $(location).attr('href'),
data: formData,
dataType: "json",
}).done(function(response) {

// get response
if (response) {

// if we got success, redirect if we got a redirect url!
if (response.success != null) {
if (typeof response.success === "string") {
window.location.replace(response.success);
}
}

// if anything else, PHP returned some errors or a message to display (i.e. 'data saved!')
else {
showMessages(response);
}
}

// Successful post, but no response came back !?
// assume success, since no 'success' response came back, thus keeping same page as is
else {
console.warn("Post sent, but no response came back!? Assuming successful post...");
}

}).fail(function(xhr, status, error) { // we get here if we don't have a proper response/json sent!

console.error("Ajax failed: " + xhr.statusText);
console.error(status);
console.error(error);

var ajaxError = {
'type': ERROR_TYPE_FATALERROR,
'message': '<strong>Ajax failure!</strong><br/><br/>' + status + '<br/><br/>' + error,
'trace': null,
'id': null,
'goback': null,
'adminMailtoLnk': 'mailto:' + 'ravenlost2@gmail.com'
};

showMessages(ajaxError);

});
}
}

/**
* showMessages()
* show error messages in page based on JSON response
* @param response JSON object holding response with (error) messages to display
*/
function showMessages(response) {

// error type
switch (response.type) {

// ----------------------------
// GLOBAL MESSAGE
// ----------------------------
case ERROR_TYPE_GLOBALMESSAGE:
$('#globalMessage').addClass('d-block');

// set global message header message type
$('#globalMessage').removeClass("error warning info");
$('#globalMessage').addClass(response.gmType);

$('#globalMessageIcon').removeClass("fa-exclamation-triangle fa-info-circle");
$('#globalMessageIcon').addClass(response.gmIcon);

$('#globalMessageTitle').empty();
$('#globalMessageTitle').append(response.gmTitle);

// set message
$('#globalMessagePH').empty();
$('#globalMessagePH').append(response.message);

// set uniq error id
if (response.id != null) {
$('#globalMessageID').addClass('d-block');
$('#globalMessageIDPH').empty();
$('#globalMessageIDPH').append(response.id);
}

// set stacktrace
if (response.trace != null) {
$('#globalMessageTrace').addClass('d-block');
$('#globalMessageTracePH').empty();
$('#globalMessageTracePH').append(response.trace);
}

// set footer
if ((response.showContactAdmin == true) || (response.goback != null)) {

$('#globalMessageFooter').addClass('d-block');

// contact admin
if (response.showContactAdmin == true) {
$('#globalMessageMailLink').addClass('d-block');
$('#globalMessageMailLinkPH').attr('href', response.adminMailtoLnk);
}

// go back
if (response.goback != null) {
$('#globalMessageGoBackLink').addClass('d-block');
$('#globalMessageGoBackLinkPH').attr('href', response.goback);
}

}

break;

// ----------------------------
// FATAL ERROR
// ----------------------------
case ERROR_TYPE_FATALERROR:

// hide content if we got a fatal as to prevent user from fiddling around and not reading the message!
$('#content').addClass('d-none');

$('#fatalError').addClass('d-block');

// set message
$('#fatalErrorMessagePH').empty();
$('#fatalErrorMessagePH').append(response.message);

// reset mailto link
$('#fatalErrorMailLink').attr('href', response.adminMailtoLnk);

// set stacktrace
if (response.trace != null) {
$('#fatalErrorTrace').addClass('d-block');
$('#fatalErrorTracePH').empty();
$('#fatalErrorTracePH').append(response.trace);
}

// set uniq error id
if (response.id != null) {
$('#fatalErrorID').addClass('d-block');
$('#fatalErrorIDPH').empty();
$('#fatalErrorIDPH').append(response.id);
}

// set 'go back' url
if (response.goback != null) {
$('#fatalErrorGoBack').addClass('d-block');
$('#fatalErrorGoBackLink').attr('href', response.goback);
}

break;

// ----------------------------
// INPUT ERROR
// ----------------------------
case ERROR_TYPE_INPUTERROR:

for (var field in response.fields) {
var msg = eval('response.fields.' + field);
$('#' + field + '_inputError').addClass('d-block')
$('#' + field + '_inputError_message').empty();
$('#' + field + '_inputError_message').append(msg);
}

break;

default:
console.error('Got an invalid error type from the response!');

}

}

/**
* validate()
* Validate if field is empty or not
* @param input form element
* @return boolean
*/
function validate(input) {

if (formSubmittedOnce === true) {

if (input.hasAttribute('required')) {
if (input.value.trim() == '') {
input.classList.remove('is-valid');
input.classList.add('is-invalid');
return false;
} else {
input.classList.remove('is-invalid');
input.classList.add('is-valid');
return true;
}
} else {
// if we get here, then any other inputs not marked as 'required' are valid
input.classList.add('is-valid');
}

}

}
<html>

<head>

<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css">

<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<!-- Popper JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>

<!-- Latest compiled JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
</head>

<body>

<form id="testfrm" class="form-group">

<div class="form-group">

<label class="form-control-label" for="username_required">Username</label>
<input type="text" name="username" aria-describedby="username_required username_inputError" class="form-control is-invalid" oninput="validate(this)" required/><br>
<div id="username_required" class="pl-1 invalid-feedback">
This field is required!
</div>

<!-- if bad username format or already taken, print form input error -->
<div id="username_inputError" class="col alert alert-danger alert-dismissible fade show mt-2 py-2 pl-3 pr-5 text-left d-none">
<small>
<strong>Error!</strong> <span id="username_inputError_message"></span>
<button type="button" aria-label="Close" class="close pt-1 pr-2" onclick="$('#username_inputError').removeClass('d-block').addClass('d-none');">×</button>
</small>
</div>

<div class="form-group">
<label class="form-control-label" for="email_required">Email</label>

<input type="text" name="email" aria-describedby="email_required email_inputError" class="form-control is-valid" oninput="validate(this)" required/><br>

<div id="email_required" class="pl-1 invalid-feedback">
This field is required!
</div>
</div>

<!-- if bad email format or already taken, print form input error -->
<div id="email_inputError" class="col alert alert-danger alert-dismissible fade show mt-2 py-2 pl-3 pr-5 text-left d-none">
<small>
<strong>Error!</strong> <span id="email_inputError_message"></span>
<button type="button" aria-label="Close" class="close pt-1 pr-2" onclick="$('#email_inputError').removeClass('d-block').addClass('d-none');">×</button>
</small>
</div>

Comment: <input type="text" name="comment" class="form-control is-valid"><br>

<input type="button" value="Submit" onclick="submitFormData('testfrm',['username','email'])" class="is-valid">
</form>

</body>

</html>

How to use invalid-feedback class with selectpicker from Bootstrap-Select?

I figured out how to do this, and more generally this is an answer for anytime you have to "manually" force an error to work with Bootstrap's native validation system. It's really hacky, but I couldn't find anything else that works.

Say you have a "selectpicker" that looks like this:

<select id="mySelect" class="selectpicker" required>
<option value="">Select an option</option>
<option>foo</option>
<option>bar</option>
</select>
<div id="error" class="invalid-feedback">Please make a selection.</div>

The error message "Please make a selection" will not show, even if the select element is invalid; it will show, however, if it also has the "d-block" class:

<div id="error" class="invalid-feedback d-block">Please make a selection.</div>

So to manually force errors, you have to use JavaScript to check for the ":invalid" CSS pseudo-class; if it has this pseudo-class, then you add the "d-block" class to your div to show the error. You can use the matches() method and classList.add():

var selector = document.getElementById("mySelect");
var errorMsg = document.getElementById("error");

if(selector.matches(":invalid"))
{
errorMsg.classList.add("d-block");
}

You do this to add the message and you can remove it by checking for ":valid" and removing "d-block" from the classList.

How to show the bootstrap 4 validation feedback using jquery?

As documented on Bootstrap's Forms documentation here:

Server side

We recommend using client side validation, but in case you require server side, you can indicate invalid and valid form fields with .is-invalid and .is-valid. Note that .invalid-feedback is also supported with these classes.

In short, you need to add the CSS class is-invalid to form controls that have validation errors. When you do this:

  • the form control will be surrounded with a red-outline to indicate that it has a validation error
  • sibling divs with the invalid-feedback CSS class will be rendered as red text

Here's a code snippet illustrating this in action with a "mock" response. Try click the Validate button:

var form = $("form").first();
$("#validate").click(function() {
var mockResponse = {
errors :
{
'first_name': 'First name must not be blank',
'last_name': 'Last name must not be blank'
}
};
$.each(mockResponse.errors, function(fieldName, error) {
let field = form.find('[name="' + fieldName + '"]');
field.addClass("is-invalid");
let immediateSibling = field.next();
if (immediateSibling.hasClass('invalid-feedback')) {
immediateSibling.text(error);
} else {
field.after("<div class='invalid-feedback'>" + error + "</div>")
}

});
return false;
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body class="bg-light">

<div class="container">
<form id="register-form" novalidate>
<div class="form-group">
<label class="sr-only" for="first_name">First Name</label>
<input type="text" id="first_name" name="first_name" value="" placeholder="First Name" class="form-control" >
</div>
<div class="form-group">
<label class="sr-only" for="last_name">Last Name</label>
<input type="text" id="last_name" name="last_name" value="" placeholder="Last Name" class="form-control" >
</div>
<div class="form-group">
<label class="sr-only" for="email">Email Name</label>
<input type="text" id="email" name="email" value="" placeholder="Email" class="form-control" >
</div>
<button id="validate" class="btn btn-primary btn-lg btn-block" type="submit">Validate</button>
</form>
</div>

issue in Bootstrap 4 validation on select field

The problem is in Your HTML, the nodes of your .input-group does not have allways the same structure. In some cases you have .invalid-feedback just after the input such as this HTML

<div class="form-group">
<label for="serialNo" class="col-form-label"><span class="text-danger">*
</span>Serial No.</label>
<input type="text" class="form-control" id="serialNo" name="serialNo">
<div class="invalid-feedback"></div>
</div>

For other fields the .invalid-feedback isn't after the input but outside from .form-group. take a look

<div class="input-group date" data-date-format="dd-M-yyyy">
<input type="text" class="form-control" id="purchaseDate" name="purchaseDate" />
<span class="input-group-text input-group-append input-group-addon">
<i class="simple-icon-calendar"></i>
</span>
</div>
<div class="invalid-feedback"></div>

This difference in HTML structure of the form made your showFieldError() and clearFieldError() not working allways as you expected, because $(element).next() don't catch the right DOM node for insert/remove the validation message. So in some cases clearFieldError remove the wrong HTML tag and this can make your selects disappear

function showFieldError(element, message) {
$(element).addClass('is-invalid');
$(element).next().html(message);
$(element).next().show();
}

function clearFieldError(element) {
$(element).removeClass('is-invalid');
$(element).removeAttr('required');
$(element).next().html('');
}

So you have to fix Your HTML to obtain the same structure for all fields. Put the <div class="invalid-feedback"></div> allways just below the select or input field. Otherwise you have to change the selector that you pass to showFieldError() and clearFieldError() functions according to your HTML

Otherwise a simply approach is to add a ID to divs with class .invalid-feedback, an ID which you can easily manage by his related input ID, something like

<div class="input-group date" data-date-format="dd-M-yyyy">
<input type="text" class="form-control" id="purchaseDate" name="purchaseDate" />
<span class="input-group-text input-group-append input-group-addon">
<i class="simple-icon-calendar"></i>
</span>
</div>
<div id="purchaseDate_err_mex" class="invalid-feedback"></div>

in this way you can pass the input name to your functions and them becomes

    function showFieldError(input_id, message) {
$('#'+input_id).addClass('is-invalid');
$('#'+ input_id +'_err_mex').html(message).show();
}

function clearFieldError(input_id) {
$('#'+input_id).removeClass('is-invalid');
//$('#'+input_id).removeAttr('required');
/* don't need to remove required attribute from mandatory fields */
$('#'+ input_name +'_err_mex').html('').hide();
}

and the validation function

function validateForm() {
var validationStatus = true;

if ($('#selectedCategory').val().length == 0) {
showFieldError('selectedCategory', 'Must not be blank');
if (validationStatus) { $('#selectedCategory').focus() };
validationStatus = false;
}

........

return validationStatus;
}

You only check if the length of all fields is more than 0, so you can validate the entire form within a loop

function validateForm() {
var validationStatus = true;
var form_inputs = $('#manageItemsForm input, #manageItemsForm select')

$.each(form_inputs,function(){

var input_id = $(this).attr('name');
clearFieldError(input_id);
if ($.trim($(this).val()).length == 0 && $(this).is("[required]")) {
showFieldError(input_id, 'Must not be blank');
if (validationStatus) { $('#'+input_id).focus() };
validationStatus = false;
}
});

return validationStatus;
}

How does is-invalid bootstrap class work?

You're using v-if="errors.foo" on the invalid-feedback div, so it will be inserted in the DOM only when errors.foo is truthy, regardless of where it is in the DOM.

As for the styling:

HTML form validation is applied via CSS’s two pseudo-classes, :invalid and :valid. It applies to <input>, <select>, and <textarea> elements.

So the placement of the .invalid-feedback div is important when using the default behaviour, which applies the styling with the general sibling combinator ~

.was-validated .form-control:invalid~.invalid-feedback {/*...*/}

There is a .was-validated class that you should add on a parent element which will apply the error styling on invalid elements.

<div :class="{'was-validated': errors.foo}">
<input class="form-control" :class="{' is-invalid': errors.foo}">
</div>
...
<div :class="{'was-validated': errors.foo}">
<div class="invalid-feedback" v-show="errors.foo">...</div>
</div>

Since it must be a general sibling, you could force the display: block with v-show or use custom CSS like d-block.

As a fallback, .is-invalid and .is-valid classes may be used instead of the pseudo-classes for server side validation. They do not require a .was-validated parent class.

This is a known problem with .input-group discussed in an issue.


If you find it's starting to get messy, you can evaluate the possibility of wrapping the inputs in components which applies your styling and then just reuse your components.

Or you could use a Vue wrapper of bootstrap, like bootstrap-vue.



Related Topics



Leave a reply



Submit