Bootstrap 4.0 Invalid-Feedback Doesn't Show

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>

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 validation classes are not being displayed in input / feedback elements

went with this simple option

/* validation and error display */
.invalid-feedback {
display: none;
}
.was-validated .invalid-feedback {
font-family: oxygen;
display: block;
}

show-errors ul {
margin: 0;
padding: 0;

li, li.invalid-feedback {
margin: 0;
padding: 0;
line-height: 1em;
}
}

show-errors + button {
margin-top:1em;
}

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>


Related Topics



Leave a reply



Submit