Dadaɖeanyi
Na nyaŋuɖoɖo xɔasi, si ŋu woate ŋu awɔ dɔ le na wò zãlawo kple HTML5 ƒe nuŋlɔɖi ƒe kpeɖodzi, to web-browser ƒe nuwɔna gbãtɔwo alo atsyã tɔxɛwo kple JavaScript dzi.
Ale si wòwɔa dɔe
Alesi agbalẽvi ƒe kpeɖodzinana wɔa dɔe kple Bootstrap enye si:
- Wozãa HTML gbalẽvi ƒe kpeɖodzinana to CSS ƒe alakpa-klas eve dzi,
:invalid
kple:valid
. Eku ɖe<input>
,<select>
, kple<textarea>
nu veviwo ŋu. - Bootstrap scopes the
:invalid
kple:valid
atsyãwo na dzila.was-validated
ƒe klass, zi geɖe la, wozãnɛ ɖe<form>
. Ne menye nenema o la, agble ɖesiaɖe si wobia si me asixɔxɔ aɖeke mele o la adze abe mesɔ o ene le axa ƒe agbatsɔtsɔ me. To mɔ sia dzi la, àte ŋu atia ɣeyiɣi si nàwɔ dɔ le wo ŋu (zi geɖe la, ne wote agbalẽviawo ɖoɖo ɖa vɔ). - Be nàgbugbɔ aɖo agbalẽvia ƒe dzedzeme (le kpɔɖeŋu me, le agbalẽvia ɖoɖo ɖa si trɔna me to AJAX zazã me la), ɖe
.was-validated
klass la ɖa le<form>
agate ŋu le eɖoɖo vɔ megbe. - Abe fallback ene,
.is-invalid
eye.is-valid
woateŋu azã klasswo ɖe pseudo-classes teƒe na server-side validation . Womebia.was-validated
dzilawo ƒe klass o. - Le mɔxexe ɖe alesi CSS wɔa dɔe ta la, míate ŋu (fifia) awɔ atsyãwo ŋudɔ ɖe a
<label>
si va doa ŋgɔ na nuŋlɔɖi dzikpɔkpɔ le DOM me JavaScript si wowɔ ɖe ɖoɖo nu ƒe kpekpeɖeŋu manɔmee o. - Egbegbe web-browserwo katã doa alɔ constraint validation API , si nye JavaScript mɔnu siwo kplɔ wo nɔewo ɖo tsɔ ɖoa kpe agbalẽviwo dzi kpɔkpɔ dzi.
- Nyaŋuɖoɖo ƒe gbedasiwo ate ŋu azã web-browser ƒe nɔnɔme gbãtɔwo (woto vovo na web-browser ɖesiaɖe, eye womate ŋu atrɔ asi le wo ŋu to CSS dzi o) alo míaƒe nyaŋuɖoɖo ƒe atsyã tɔxɛwo kple HTML kple CSS bubuwo.
- Àte ŋu ana gbedasi siwo wowɔ ɖe ɖoɖo nu ƒe kpeɖodzinyawo kple
setCustomValidity
le JavaScript me.
Esi esia le susu me na wò la, bu wɔwɔfia siwo gbɔna ŋu na míaƒe agbalẽvi ƒe kpeɖodzi ƒe atsyã tɔxɛwo, server-side classes siwo woate ŋu atia, kple browser ƒe defaults.
Atsyã siwo wowɔ ɖe ɖoɖo nu
Le Bootstrap ƒe nuŋlɔɖi ƒe kpeɖodzi gbedasi tɔxɛwo gome la, ahiã be nàtsɔ novalidate
boolean nɔnɔmea akpe ɖe wò <form>
. Esia na be browser ƒe nyaŋuɖoɖo ƒe aɖaŋuɖoɖo siwo woɖo ɖi la mewɔa dɔ o, gake eganaa mɔnukpɔkpɔ ame be wòakpɔ agbalẽviawo ƒe kpeɖodzi APIwo le JavaScript me. Dze agbagba nàtsɔ agbalẽvi si le ete la aɖo ɖa; míaƒe JavaScript la axe mɔ ɖe submit ƒe dzesi la nu eye wòagblɔ nyaŋuɖoɖowo na wò. Ne èle agbagba dzem be yeaɖoe ɖa la, àkpɔ :invalid
kple :valid
atsyã siwo wozã ɖe wò agbalẽvia dzi kpɔkpɔ ŋu.
Nyaŋuɖoɖo ƒe atsyã tɔxɛwo zãa amadede tɔxɛwo, liƒowo, susu ƒe atsyãwo, kple megbe dzesiwo be woatsɔ aɖo nyaŋuɖoɖowo gbɔ nyuie wu. Megbenyawo ƒe nɔnɔmetatawo na <select>
s koe li kple .form-select
, eye menye .form-control
.
<form class="row g-3 needs-validation" novalidate>
<div class="col-md-4">
<label for="validationCustom01" class="form-label">First name</label>
<input type="text" class="form-control" id="validationCustom01" value="Mark" required>
<div class="valid-feedback">
Looks good!
</div>
</div>
<div class="col-md-4">
<label for="validationCustom02" class="form-label">Last name</label>
<input type="text" class="form-control" id="validationCustom02" value="Otto" required>
<div class="valid-feedback">
Looks good!
</div>
</div>
<div class="col-md-4">
<label for="validationCustomUsername" class="form-label">Username</label>
<div class="input-group has-validation">
<span class="input-group-text" id="inputGroupPrepend">@</span>
<input type="text" class="form-control" id="validationCustomUsername" aria-describedby="inputGroupPrepend" required>
<div class="invalid-feedback">
Please choose a username.
</div>
</div>
</div>
<div class="col-md-6">
<label for="validationCustom03" class="form-label">City</label>
<input type="text" class="form-control" id="validationCustom03" required>
<div class="invalid-feedback">
Please provide a valid city.
</div>
</div>
<div class="col-md-3">
<label for="validationCustom04" class="form-label">State</label>
<select class="form-select" id="validationCustom04" required>
<option selected disabled value="">Choose...</option>
<option>...</option>
</select>
<div class="invalid-feedback">
Please select a valid state.
</div>
</div>
<div class="col-md-3">
<label for="validationCustom05" class="form-label">Zip</label>
<input type="text" class="form-control" id="validationCustom05" required>
<div class="invalid-feedback">
Please provide a valid zip.
</div>
</div>
<div class="col-12">
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="invalidCheck" required>
<label class="form-check-label" for="invalidCheck">
Agree to terms and conditions
</label>
<div class="invalid-feedback">
You must agree before submitting.
</div>
</div>
</div>
<div class="col-12">
<button class="btn btn-primary" type="submit">Submit form</button>
</div>
</form>
// Example starter JavaScript for disabling form submissions if there are invalid fields
(() => {
'use strict'
// Fetch all the forms we want to apply custom Bootstrap validation styles to
const forms = document.querySelectorAll('.needs-validation')
// Loop over them and prevent submission
Array.from(forms).forEach(form => {
form.addEventListener('submit', event => {
if (!form.checkValidity()) {
event.preventDefault()
event.stopPropagation()
}
form.classList.add('was-validated')
}, false)
})
})()
Browser ƒe ɖoɖowɔɖiwo
Mètsɔ ɖeke le custom validation feedback gbedasiwo alo JavaScript ŋɔŋlɔ me be nàtrɔ agbalẽvi ƒe nuwɔnawo oa? Wo katã nyuie, àte ŋu azã browser la ƒe defaults. Te agbalẽvi si le ete la ɖoɖo ɖa kpɔ. Le wò browser kple OS nu la, àkpɔ nyaŋuɖoɖo ƒe atsyã si to vovo vie.
Togbɔ be womateŋu awɔ nyaŋuɖoɖo ƒe atsyã siawo kple CSS o hã la, àteŋu atrɔ asi le nyaŋuɖoɖo ƒe nuŋɔŋlɔa ŋu kokoko to JavaScript dzi.
<form class="row g-3">
<div class="col-md-4">
<label for="validationDefault01" class="form-label">First name</label>
<input type="text" class="form-control" id="validationDefault01" value="Mark" required>
</div>
<div class="col-md-4">
<label for="validationDefault02" class="form-label">Last name</label>
<input type="text" class="form-control" id="validationDefault02" value="Otto" required>
</div>
<div class="col-md-4">
<label for="validationDefaultUsername" class="form-label">Username</label>
<div class="input-group">
<span class="input-group-text" id="inputGroupPrepend2">@</span>
<input type="text" class="form-control" id="validationDefaultUsername" aria-describedby="inputGroupPrepend2" required>
</div>
</div>
<div class="col-md-6">
<label for="validationDefault03" class="form-label">City</label>
<input type="text" class="form-control" id="validationDefault03" required>
</div>
<div class="col-md-3">
<label for="validationDefault04" class="form-label">State</label>
<select class="form-select" id="validationDefault04" required>
<option selected disabled value="">Choose...</option>
<option>...</option>
</select>
</div>
<div class="col-md-3">
<label for="validationDefault05" class="form-label">Zip</label>
<input type="text" class="form-control" id="validationDefault05" required>
</div>
<div class="col-12">
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="invalidCheck2" required>
<label class="form-check-label" for="invalidCheck2">
Agree to terms and conditions
</label>
</div>
</div>
<div class="col-12">
<button class="btn btn-primary" type="submit">Submit form</button>
</div>
</form>
Server ƒe akpa dzi
Míele aɖaŋu ɖom be nàzã client-side validation, gake nenye be èhiã server-side validation la, àteŋu afia agbalẽvi ƒe akpa siwo mesɔ o eye wosɔ kple .is-invalid
kple .is-valid
. De dzesii be .invalid-feedback
wodoa alɔe hã kple klass siawo.
Le agble siwo mesɔ o gome la, kpɔ egbɔ be nyaŋuɖoɖo/vodada ƒe gbedasi si mesɔ o la do ƒome kple agbalẽvi ƒe akpa si sɔ la zazã (de dzesii be nɔnɔme sia ɖe mɔ be woayɔ nusiwo aria-describedby
wu ɖeka , nenye be agblea fia asi agbalẽvi ƒe nuŋɔŋlɔ bubuwo xoxo).id
Be woaɖɔ kuxiwo ɖo le liƒo ƒe didime ŋu la, nyawo tsɔtsɔ de eme ƒe ƒuƒoƒowo hiã .has-validation
klass bubu.
<form class="row g-3">
<div class="col-md-4">
<label for="validationServer01" class="form-label">First name</label>
<input type="text" class="form-control is-valid" id="validationServer01" value="Mark" required>
<div class="valid-feedback">
Looks good!
</div>
</div>
<div class="col-md-4">
<label for="validationServer02" class="form-label">Last name</label>
<input type="text" class="form-control is-valid" id="validationServer02" value="Otto" required>
<div class="valid-feedback">
Looks good!
</div>
</div>
<div class="col-md-4">
<label for="validationServerUsername" class="form-label">Username</label>
<div class="input-group has-validation">
<span class="input-group-text" id="inputGroupPrepend3">@</span>
<input type="text" class="form-control is-invalid" id="validationServerUsername" aria-describedby="inputGroupPrepend3 validationServerUsernameFeedback" required>
<div id="validationServerUsernameFeedback" class="invalid-feedback">
Please choose a username.
</div>
</div>
</div>
<div class="col-md-6">
<label for="validationServer03" class="form-label">City</label>
<input type="text" class="form-control is-invalid" id="validationServer03" aria-describedby="validationServer03Feedback" required>
<div id="validationServer03Feedback" class="invalid-feedback">
Please provide a valid city.
</div>
</div>
<div class="col-md-3">
<label for="validationServer04" class="form-label">State</label>
<select class="form-select is-invalid" id="validationServer04" aria-describedby="validationServer04Feedback" required>
<option selected disabled value="">Choose...</option>
<option>...</option>
</select>
<div id="validationServer04Feedback" class="invalid-feedback">
Please select a valid state.
</div>
</div>
<div class="col-md-3">
<label for="validationServer05" class="form-label">Zip</label>
<input type="text" class="form-control is-invalid" id="validationServer05" aria-describedby="validationServer05Feedback" required>
<div id="validationServer05Feedback" class="invalid-feedback">
Please provide a valid zip.
</div>
</div>
<div class="col-12">
<div class="form-check">
<input class="form-check-input is-invalid" type="checkbox" value="" id="invalidCheck3" aria-describedby="invalidCheck3Feedback" required>
<label class="form-check-label" for="invalidCheck3">
Agree to terms and conditions
</label>
<div id="invalidCheck3Feedback" class="invalid-feedback">
You must agree before submitting.
</div>
</div>
</div>
<div class="col-12">
<button class="btn btn-primary" type="submit">Submit form</button>
</div>
</form>
Nusiwo wodo alɔe
Dzesidede atsyãwo li na agbalẽvi ƒe dziɖuɖu kple akpa siwo gbɔna:
<input>
s kple<textarea>
s kple.form-control
(si me ɖeka.form-control
le nyawo tsɔtsɔ de eme ƒe ƒuƒoƒowo me hã le) .<select>
s kple.form-select
.form-check
s
<form class="was-validated">
<div class="mb-3">
<label for="validationTextarea" class="form-label">Textarea</label>
<textarea class="form-control" id="validationTextarea" placeholder="Required example textarea" required></textarea>
<div class="invalid-feedback">
Please enter a message in the textarea.
</div>
</div>
<div class="form-check mb-3">
<input type="checkbox" class="form-check-input" id="validationFormCheck1" required>
<label class="form-check-label" for="validationFormCheck1">Check this checkbox</label>
<div class="invalid-feedback">Example invalid feedback text</div>
</div>
<div class="form-check">
<input type="radio" class="form-check-input" id="validationFormCheck2" name="radio-stacked" required>
<label class="form-check-label" for="validationFormCheck2">Toggle this radio</label>
</div>
<div class="form-check mb-3">
<input type="radio" class="form-check-input" id="validationFormCheck3" name="radio-stacked" required>
<label class="form-check-label" for="validationFormCheck3">Or toggle this other radio</label>
<div class="invalid-feedback">More example invalid feedback text</div>
</div>
<div class="mb-3">
<select class="form-select" required aria-label="select example">
<option value="">Open this select menu</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
<div class="invalid-feedback">Example invalid select feedback</div>
</div>
<div class="mb-3">
<input type="file" class="form-control" aria-label="file example" required>
<div class="invalid-feedback">Example invalid form file feedback</div>
</div>
<div class="mb-3">
<button class="btn btn-primary" type="submit" disabled>Submit form</button>
</div>
</form>
Dɔwɔnu ƒe Aɖaŋuɖoɖowo
Ne wò agbalẽvi ƒe ɖoɖo ɖe mɔ ɖe eŋu la, àteŋu aɖɔli .{valid|invalid}-feedback
klassawo ɖe .{valid|invalid}-tooltip
klasswo ta be woaɖe kpeɖodzinyaŋuɖoɖo afia le dɔwɔnu ƒe aɖaŋuɖoɖo si wowɔ ɖe atsyã me. Kpɔ egbɔ be dzila aɖe position: relative
le asiwò hena dɔwɔnu ƒe aɖaŋuɖoɖo ƒe ɖoɖowɔwɔ. Le kpɔɖeŋu si le ete me la, esia le míaƒe kɔlam ƒe klasswo si xoxo, gake wò dɔa ateŋu abia ɖoɖo bubu.
<form class="row g-3 needs-validation" novalidate>
<div class="col-md-4 position-relative">
<label for="validationTooltip01" class="form-label">First name</label>
<input type="text" class="form-control" id="validationTooltip01" value="Mark" required>
<div class="valid-tooltip">
Looks good!
</div>
</div>
<div class="col-md-4 position-relative">
<label for="validationTooltip02" class="form-label">Last name</label>
<input type="text" class="form-control" id="validationTooltip02" value="Otto" required>
<div class="valid-tooltip">
Looks good!
</div>
</div>
<div class="col-md-4 position-relative">
<label for="validationTooltipUsername" class="form-label">Username</label>
<div class="input-group has-validation">
<span class="input-group-text" id="validationTooltipUsernamePrepend">@</span>
<input type="text" class="form-control" id="validationTooltipUsername" aria-describedby="validationTooltipUsernamePrepend" required>
<div class="invalid-tooltip">
Please choose a unique and valid username.
</div>
</div>
</div>
<div class="col-md-6 position-relative">
<label for="validationTooltip03" class="form-label">City</label>
<input type="text" class="form-control" id="validationTooltip03" required>
<div class="invalid-tooltip">
Please provide a valid city.
</div>
</div>
<div class="col-md-3 position-relative">
<label for="validationTooltip04" class="form-label">State</label>
<select class="form-select" id="validationTooltip04" required>
<option selected disabled value="">Choose...</option>
<option>...</option>
</select>
<div class="invalid-tooltip">
Please select a valid state.
</div>
</div>
<div class="col-md-3 position-relative">
<label for="validationTooltip05" class="form-label">Zip</label>
<input type="text" class="form-control" id="validationTooltip05" required>
<div class="invalid-tooltip">
Please provide a valid zip.
</div>
</div>
<div class="col-12">
<button class="btn btn-primary" type="submit">Submit form</button>
</div>
</form>
Sass ƒe nyawo
Nusiwo trɔna
$form-feedback-margin-top: $form-text-margin-top;
$form-feedback-font-size: $form-text-font-size;
$form-feedback-font-style: $form-text-font-style;
$form-feedback-valid-color: $success;
$form-feedback-invalid-color: $danger;
$form-feedback-icon-valid-color: $form-feedback-valid-color;
$form-feedback-icon-valid: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'><path fill='#{$form-feedback-icon-valid-color}' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/></svg>");
$form-feedback-icon-invalid-color: $form-feedback-invalid-color;
$form-feedback-icon-invalid: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='#{$form-feedback-icon-invalid-color}'><circle cx='6' cy='6' r='4.5'/><path stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/><circle cx='6' cy='8.2' r='.6' fill='#{$form-feedback-icon-invalid-color}' stroke='none'/></svg>");
Nusiwo wotsɔ tsakae
Woƒo mixin eve nu ƒu ɖekae, to míaƒe loop dzi , be woawɔ míaƒe nuŋlɔɖi ƒe kpeɖodzi nyaŋuɖoɖo ƒe atsyãwo.
@mixin form-validation-state-selector($state) {
@if ($state == "valid" or $state == "invalid") {
.was-validated #{if(&, "&", "")}:#{$state},
#{if(&, "&", "")}.is-#{$state} {
@content;
}
} @else {
#{if(&, "&", "")}.is-#{$state} {
@content;
}
}
}
@mixin form-validation-state(
$state,
$color,
$icon,
$tooltip-color: color-contrast($color),
$tooltip-bg-color: rgba($color, $form-feedback-tooltip-opacity),
$focus-box-shadow: 0 0 $input-btn-focus-blur $input-focus-width rgba($color, $input-btn-focus-color-opacity)
) {
.#{$state}-feedback {
display: none;
width: 100%;
margin-top: $form-feedback-margin-top;
@include font-size($form-feedback-font-size);
font-style: $form-feedback-font-style;
color: $color;
}
.#{$state}-tooltip {
position: absolute;
top: 100%;
z-index: 5;
display: none;
max-width: 100%; // Contain to parent when possible
padding: $form-feedback-tooltip-padding-y $form-feedback-tooltip-padding-x;
margin-top: .1rem;
@include font-size($form-feedback-tooltip-font-size);
line-height: $form-feedback-tooltip-line-height;
color: $tooltip-color;
background-color: $tooltip-bg-color;
@include border-radius($form-feedback-tooltip-border-radius);
}
@include form-validation-state-selector($state) {
~ .#{$state}-feedback,
~ .#{$state}-tooltip {
display: block;
}
}
.form-control {
@include form-validation-state-selector($state) {
border-color: $color;
@if $enable-validation-icons {
padding-right: $input-height-inner;
background-image: escape-svg($icon);
background-repeat: no-repeat;
background-position: right $input-height-inner-quarter center;
background-size: $input-height-inner-half $input-height-inner-half;
}
&:focus {
border-color: $color;
box-shadow: $focus-box-shadow;
}
}
}
// stylelint-disable-next-line selector-no-qualifying-type
textarea.form-control {
@include form-validation-state-selector($state) {
@if $enable-validation-icons {
padding-right: $input-height-inner;
background-position: top $input-height-inner-quarter right $input-height-inner-quarter;
}
}
}
.form-select {
@include form-validation-state-selector($state) {
border-color: $color;
@if $enable-validation-icons {
&:not([multiple]):not([size]),
&:not([multiple])[size="1"] {
padding-right: $form-select-feedback-icon-padding-end;
background-image: escape-svg($form-select-indicator), escape-svg($icon);
background-position: $form-select-bg-position, $form-select-feedback-icon-position;
background-size: $form-select-bg-size, $form-select-feedback-icon-size;
}
}
&:focus {
border-color: $color;
box-shadow: $focus-box-shadow;
}
}
}
.form-control-color {
@include form-validation-state-selector($state) {
@if $enable-validation-icons {
width: add($form-color-width, $input-height-inner);
}
}
}
.form-check-input {
@include form-validation-state-selector($state) {
border-color: $color;
&:checked {
background-color: $color;
}
&:focus {
box-shadow: $focus-box-shadow;
}
~ .form-check-label {
color: $color;
}
}
}
.form-check-inline .form-check-input {
~ .#{$state}-feedback {
margin-left: .5em;
}
}
.input-group {
> .form-control:not(:focus),
> .form-select:not(:focus),
> .form-floating:not(:focus-within) {
@include form-validation-state-selector($state) {
@if $state == "valid" {
z-index: 3;
} @else if $state == "invalid" {
z-index: 4;
}
}
}
}
}
Anyigbatata
Esia nye kpeɖodzi Sass anyigbatata tso _variables.scss
. Trɔ asi le esia ŋu alo kekee ɖe enu be nàwɔ nɔnɔme vovovowo alo bubuwo.
$form-validation-states: (
"valid": (
"color": $form-feedback-valid-color,
"icon": $form-feedback-icon-valid
),
"invalid": (
"color": $form-feedback-invalid-color,
"icon": $form-feedback-icon-invalid
)
);
Maps of $form-validation-states
ateŋu akpɔ parameter etɔ̃ siwo woateŋu awɔ be woatsɔ axe mɔ ɖe dɔwɔnu ƒe aɖaŋuɖoɖowo kple susu ƒe atsyãwo nu.
Xatsa
Wozãnɛ tsɔ gbugbɔa $form-validation-states
anyigbatata ƒe asixɔxɔwo dzi tsɔ wɔa míaƒe kpeɖodzi ƒe atsyãwo. Tɔtrɔ ɖesiaɖe si woawɔ le Sass ƒe anyigbatata si le etame ŋu la adze le wò CSS si nèƒo ƒu me to loop sia dzi.
@each $state, $data in $form-validation-states {
@include form-validation-state($state, $data...);
}
Trɔtrɔ ɖe nɔnɔmewo ŋu
Woateŋu atrɔ asi le kpeɖodzi nɔnɔmewo ŋu to Sass dzi kple $form-validation-states
anyigbatata. Sass ƒe anyigbatata sia si le míaƒe _variables.scss
faɛl me lae nye alesi míewɔa default valid
/ invalid
validation states. Nusiwo le emee nye anyigbatata si wotsɔ ƒo ƒui hena tɔtrɔ ɖe nɔnɔme ɖesiaɖe ƒe amadede, dzesi, dɔwɔnu ƒe amadede, kple ŋkuléleɖenuŋu ƒe vɔvɔli ŋu. Togbɔ be dukɔ bubu aɖeke medoa alɔ web-browserwo o hã la, amesiwo zãa atsyã siwo wowɔ ɖe ɖoɖo nu ate ŋu atsɔ agbalẽvi ƒe nyaŋuɖoɖo siwo sesẽ wu akpe ɖe eŋu bɔbɔe.