Fixes #20398: Rely on browser-native form field validation (#20401)

This commit is contained in:
Jeremy Stretch 2025-09-19 16:13:47 -04:00 committed by GitHub
parent 07a53c8315
commit 6547a16ab6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 12 additions and 47 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,53 +1,23 @@
import { getElements, scrollTo } from '../util'; import { getElements } from '../util';
function handleFormSubmit(event: Event, form: HTMLFormElement): void { function handleFormSubmit(): void {
// Automatically select all options in any <select> with the "select-all" class. This is useful for // Automatically select all options in any <select> with the "select-all" class. This is useful for
// multi-select fields that are used to add/remove choices. // multi-select fields that are used to add/remove choices.
for (const element of getElements<HTMLOptionElement>('select.select-all option')) { for (const element of getElements<HTMLOptionElement>('select.select-all option')) {
element.selected = true; element.selected = true;
} }
// Track the names of each invalid field.
const invalids = new Set<string>();
for (const element of form.querySelectorAll<FormControls>('*[name]')) {
if (!element.validity.valid) {
invalids.add(element.name);
// If the field is invalid, but doesn't contain the .is-invalid class, add it.
if (!element.classList.contains('is-invalid')) {
element.classList.add('is-invalid');
}
} else {
// If the field is valid, but contains the .is-invalid class, remove it.
if (element.classList.contains('is-invalid')) {
element.classList.remove('is-invalid');
}
}
}
if (invalids.size !== 0) {
// If there are invalid fields, pick the first field and scroll to it.
const firstInvalid = form.elements.namedItem(Array.from(invalids)[0]) as Element;
scrollTo(firstInvalid);
// If the form has invalid fields, don't submit it.
event.preventDefault();
}
} }
/** /**
* Attach an event listener to each form's submitter (button[type=submit]). When called, the * Attach event listeners to each form's submit/reset buttons.
* callback checks the validity of each form field and adds the appropriate Bootstrap CSS class
* based on the field's validity.
*/ */
export function initFormElements(): void { export function initFormElements(): void {
for (const form of getElements('form')) { for (const form of getElements('form')) {
// Find each of the form's submitters. Most object edit forms have a "Create" and // Find each of the form's submit buttons.
// a "Create & Add", so we need to add a listener to both.
const submitters = form.querySelectorAll<HTMLButtonElement>('button[type=submit]'); const submitters = form.querySelectorAll<HTMLButtonElement>('button[type=submit]');
for (const submitter of submitters) { for (const submitter of submitters) {
// Add the event listener to each submitter. // Add the event listener to each submitter.
submitter.addEventListener('click', (event: Event) => handleFormSubmit(event, form)); submitter.addEventListener('click', () => handleFormSubmit());
} }
// Initialize any reset buttons so that when clicked, the page is reloaded without query parameters. // Initialize any reset buttons so that when clicked, the page is reloaded without query parameters.

View File

@ -65,7 +65,6 @@
<div class="col-md-4"> <div class="col-md-4">
{{ form.length_unit }} {{ form.length_unit }}
</div> </div>
<div class="invalid-feedback"></div>
</div> </div>
{% render_field form.tags %} {% render_field form.tags %}
</div> </div>

View File

@ -52,10 +52,6 @@
<div class="form-text text-danger"> <div class="form-text text-danger">
{% for error in field.errors %}{{ error }}{% if not forloop.last %}<br />{% endif %}{% endfor %} {% for error in field.errors %}{{ error }}{% if not forloop.last %}<br />{% endif %}{% endfor %}
</div> </div>
{% elif field.field.required %}
<div class="invalid-feedback">
{% trans "This field is required" %}.
</div>
{% endif %} {% endif %}
{# Help text #} {# Help text #}