fix(forms): erreurs de validation par champ au blur
- Erreurs affichées sous chaque champ obligatoire (fr-error-text DSFR) au lieu d'un message global en haut du formulaire - Déclenchement sur blur (sortie du champ) et effacement sur input - Concerne la modale édition API et la modale catégorie Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
@@ -242,13 +242,19 @@ import { ApiEntry, Category } from '@datacat/shared';
|
|||||||
@if (editError()) {
|
@if (editError()) {
|
||||||
<div class="fr-alert fr-alert--error fr-mb-2w"><p>{{ editError() }}</p></div>
|
<div class="fr-alert fr-alert--error fr-mb-2w"><p>{{ editError() }}</p></div>
|
||||||
}
|
}
|
||||||
<div class="fr-input-group fr-mb-2w">
|
<div class="fr-input-group fr-mb-2w" [class.fr-input-group--error]="editTitleError()">
|
||||||
<label class="fr-label" for="edit-title">Titre <span style="color:var(--text-default-error)">*</span></label>
|
<label class="fr-label" for="edit-title">Titre <span style="color:var(--text-default-error)">*</span></label>
|
||||||
<input id="edit-title" class="fr-input" type="text" [value]="editTitle()" (input)="editTitle.set($any($event.target).value)" />
|
<input id="edit-title" class="fr-input" [class.fr-input--error]="editTitleError()" type="text" [value]="editTitle()"
|
||||||
|
(input)="editTitle.set($any($event.target).value); editTitleError.set(false)"
|
||||||
|
(blur)="editTitleError.set(!editTitle().trim())" />
|
||||||
|
@if (editTitleError()) { <p class="fr-error-text">Le titre est obligatoire.</p> }
|
||||||
</div>
|
</div>
|
||||||
<div class="fr-input-group fr-mb-2w">
|
<div class="fr-input-group fr-mb-2w" [class.fr-input-group--error]="editVersionError()">
|
||||||
<label class="fr-label" for="edit-version">Version <span style="color:var(--text-default-error)">*</span></label>
|
<label class="fr-label" for="edit-version">Version <span style="color:var(--text-default-error)">*</span></label>
|
||||||
<input id="edit-version" class="fr-input" type="text" [value]="editVersion()" (input)="editVersion.set($any($event.target).value)" />
|
<input id="edit-version" class="fr-input" [class.fr-input--error]="editVersionError()" type="text" [value]="editVersion()"
|
||||||
|
(input)="editVersion.set($any($event.target).value); editVersionError.set(false)"
|
||||||
|
(blur)="editVersionError.set(!editVersion().trim())" />
|
||||||
|
@if (editVersionError()) { <p class="fr-error-text">La version est obligatoire.</p> }
|
||||||
</div>
|
</div>
|
||||||
<div class="fr-select-group fr-mb-2w">
|
<div class="fr-select-group fr-mb-2w">
|
||||||
<label class="fr-label" for="edit-category">Catégorie</label>
|
<label class="fr-label" for="edit-category">Catégorie</label>
|
||||||
@@ -315,6 +321,8 @@ export class ApiDetailComponent implements OnInit, OnDestroy {
|
|||||||
showEditModal = signal(false);
|
showEditModal = signal(false);
|
||||||
editLoading = signal(false);
|
editLoading = signal(false);
|
||||||
editError = signal<string | null>(null);
|
editError = signal<string | null>(null);
|
||||||
|
editTitleError = signal(false);
|
||||||
|
editVersionError = signal(false);
|
||||||
categories = signal<Category[]>([]);
|
categories = signal<Category[]>([]);
|
||||||
editTitle = signal('');
|
editTitle = signal('');
|
||||||
editVersion = signal('');
|
editVersion = signal('');
|
||||||
@@ -365,6 +373,8 @@ export class ApiDetailComponent implements OnInit, OnDestroy {
|
|||||||
this.editContactTechnical.set(entry.contactTechnical ?? '');
|
this.editContactTechnical.set(entry.contactTechnical ?? '');
|
||||||
this.editAccessRights.set(entry.accessRights ?? '');
|
this.editAccessRights.set(entry.accessRights ?? '');
|
||||||
this.editError.set(null);
|
this.editError.set(null);
|
||||||
|
this.editTitleError.set(false);
|
||||||
|
this.editVersionError.set(false);
|
||||||
this.categoryService.list().subscribe((res) => this.categories.set(res.items));
|
this.categoryService.list().subscribe((res) => this.categories.set(res.items));
|
||||||
this.showEditModal.set(true);
|
this.showEditModal.set(true);
|
||||||
}
|
}
|
||||||
@@ -374,10 +384,9 @@ export class ApiDetailComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
|
|
||||||
submitEdit() {
|
submitEdit() {
|
||||||
if (!this.editTitle().trim() || !this.editVersion().trim()) {
|
this.editTitleError.set(!this.editTitle().trim());
|
||||||
this.editError.set('Le titre et la version sont obligatoires.');
|
this.editVersionError.set(!this.editVersion().trim());
|
||||||
return;
|
if (!this.editTitle().trim() || !this.editVersion().trim()) return;
|
||||||
}
|
|
||||||
this.editLoading.set(true);
|
this.editLoading.set(true);
|
||||||
this.apiService.update(this.id, {
|
this.apiService.update(this.id, {
|
||||||
title: this.editTitle().trim(),
|
title: this.editTitle().trim(),
|
||||||
|
|||||||
@@ -246,13 +246,15 @@ import { forkJoin } from 'rxjs';
|
|||||||
<p>{{ formError() }}</p>
|
<p>{{ formError() }}</p>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div class="fr-input-group fr-mb-2w">
|
<div class="fr-input-group fr-mb-2w" [class.fr-input-group--error]="formNameError()">
|
||||||
<label class="fr-label" for="form-name">
|
<label class="fr-label" for="form-name">
|
||||||
Nom <span style="color:var(--text-default-error)">*</span>
|
Nom <span style="color:var(--text-default-error)">*</span>
|
||||||
</label>
|
</label>
|
||||||
<input id="form-name" class="fr-input" type="text"
|
<input id="form-name" class="fr-input" [class.fr-input--error]="formNameError()" type="text"
|
||||||
[value]="formName()"
|
[value]="formName()"
|
||||||
(input)="formName.set($any($event.target).value)" />
|
(input)="formName.set($any($event.target).value); formNameError.set(false)"
|
||||||
|
(blur)="formNameError.set(!formName().trim())" />
|
||||||
|
@if (formNameError()) { <p class="fr-error-text">Le nom est obligatoire.</p> }
|
||||||
</div>
|
</div>
|
||||||
<div class="fr-input-group fr-mb-3w">
|
<div class="fr-input-group fr-mb-3w">
|
||||||
<label class="fr-label" for="form-desc">
|
<label class="fr-label" for="form-desc">
|
||||||
@@ -307,6 +309,7 @@ export class BrowseComponent implements OnInit {
|
|||||||
formName = signal('');
|
formName = signal('');
|
||||||
formDescription = signal('');
|
formDescription = signal('');
|
||||||
formError = signal<string | null>(null);
|
formError = signal<string | null>(null);
|
||||||
|
formNameError = signal(false);
|
||||||
formLoading = signal(false);
|
formLoading = signal(false);
|
||||||
|
|
||||||
/* Ancêtres = breadcrumb sans le nœud courant (déjà dans le h1) */
|
/* Ancêtres = breadcrumb sans le nœud courant (déjà dans le h1) */
|
||||||
@@ -346,6 +349,7 @@ export class BrowseComponent implements OnInit {
|
|||||||
this.formName.set('');
|
this.formName.set('');
|
||||||
this.formDescription.set('');
|
this.formDescription.set('');
|
||||||
this.formError.set(null);
|
this.formError.set(null);
|
||||||
|
this.formNameError.set(false);
|
||||||
this.showFormModal.set(true);
|
this.showFormModal.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,6 +359,7 @@ export class BrowseComponent implements OnInit {
|
|||||||
this.formName.set(cat.name);
|
this.formName.set(cat.name);
|
||||||
this.formDescription.set(cat.description ?? '');
|
this.formDescription.set(cat.description ?? '');
|
||||||
this.formError.set(null);
|
this.formError.set(null);
|
||||||
|
this.formNameError.set(false);
|
||||||
this.showFormModal.set(true);
|
this.showFormModal.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -364,9 +369,10 @@ export class BrowseComponent implements OnInit {
|
|||||||
|
|
||||||
submitForm() {
|
submitForm() {
|
||||||
if (!this.formName().trim()) {
|
if (!this.formName().trim()) {
|
||||||
this.formError.set('Le nom est obligatoire.');
|
this.formNameError.set(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.formNameError.set(false);
|
||||||
this.formLoading.set(true);
|
this.formLoading.set(true);
|
||||||
const name = this.formName().trim();
|
const name = this.formName().trim();
|
||||||
const description = this.formDescription().trim() || undefined;
|
const description = this.formDescription().trim() || undefined;
|
||||||
|
|||||||
Reference in New Issue
Block a user