Bootstrap 4 Invalid Feedback with Input Group Not Displaying

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;
}

Why is Bootstrap 4 Beta .invalid-feedback displaying when field is valid?

I'm having the same issue. Apparently it's a known bug with BS 4.0.0beta according to this issue on Bootstrap's GitHub Issue Tracker.

There is already a patch merged, but it will only be released together with the second beta, which will probably take some weeks.

In the meantime, you can apply the fix yourself on the mixins/_form.scss file, or if you prefer or need to simply override the wrong rule, you can do this:

.was-validated .form-control:valid ~ .invalid-feedback,
.was-validated .form-control:valid ~ .invalid-tooltip,
.form-control.is-valid ~ .invalid-feedback,
.form-control.is-valid ~ .invalid-tooltip,
.was-validated .custom-select:valid ~ .invalid-feedback,
.was-validated .custom-select:valid ~ .invalid-tooltip,
.custom-select.is-valid ~ .invalid-feedback,
.custom-select.is-valid ~ .invalid-tooltip {
display: none;
}

.was-validated .form-control:valid ~ .valid-feedback,
.was-validated .form-control:valid ~ .valid-tooltip,
.form-control.is-valid ~ .valid-feedback,
.form-control.is-valid ~ .valid-tooltip,
.was-validated .custom-select:valid ~ .valid-feedback,
.was-validated .custom-select:valid ~ .valid-tooltip,
.custom-select.is-valid ~ .valid-feedback,
.custom-select.is-valid ~ .valid-tooltip {
display: block;
}

The first rule will override and make sure the invalid stuff remains hidden when the input is valid, and the second rule shows the valid feedback and tooltips when the input is valid.

Please note that this monstrosity of CSS comes directly from the compiled Bootstrap from their CDN, you can always remove the selectors you're not using to make this smaller, but the best way is always to edit the source SASS files. I needed to do it this way because I'm using the CDN and only have the minified CSS to work with.



Related Topics



Leave a reply



Submit