Aller au contenu principal

18-1 Réutilisation du formulaire de création

Essayons de réutiliser le même formulaire que la création, mais pour la modification aussi! Cela nous évitera de dupliquer une bonne partie de la logique de présentation.

Associer une route pour la modification

Premièrement, créez une route pour la modification vers le composant de création.

src/app/app.routes.ts
export const routes: Routes = [
{
path: '',
redirectTo: 'projets',
pathMatch: 'full'
},
{
path: 'projets',
component: ProjetsIndex
},
{
path: 'projets/creer',
component: ProjetCreer
},
{
path: 'projets/:id',
component: ProjetDetail
},
{
path: 'projets/:id/modifier',
component: ProjetCreer
}
];
astuce

Plusieurs routes peuvent pointer vers le même composant!

Faire un lien vers la page de modification à partir de ProjetDetailPage

Ajoutez un bouton Modifier sur la page detail pour accéder à la page de modification.

info

Des row et col ont été ajoutées pour disposer le contenu et aligner le bouton Modifier à droite du titre. Cela est optionnel, il s'agit simplement de positionnement et d'esthétisme visuel.

src/app/features/projets/pages/projet-detail.ts
@Component({
selector: 'app-projet-detail',
imports: [
RouterLink
],
template: `
@if (projet) {
<div class="row">
<div class="col-lg-8">
<h1>{{projet.nom}}</h1>
</div>
<div class="col-lg-4 d-flex align-items-center justify-content-lg-end">
<a class="btn btn-secondary" [routerLink]="['/projets', projet.id, 'modifier']">Modifier</a>
</div>
</div>
<div class="row mt-3">
<div class="col">
<p>{{projet.description}}</p>
</div>
</div>
}
`,
styles: ``
})

Test dans le navigateur

Essayez d'appuyer sur le bouton Modifier dans votre navigateur, vous devriez être dirigé vers la page de création.

info

Ne vous inquietez pas, nous verrons comment changer le texte faisant référence à la création pour supporter aussi la modification.

Charger les données du projet à modifier

Lors de la modification, il est important de charger le formulaire avec les données à modifier! Pour cela, lors de l'initialisation du composant, on peut utiliser la fonction de service obtenir().

Pour cela, on doit savoir si nous sommes en mode "édition" ou en mode "création". La facteur différentiation est la présence d'un id de projet dans l'URL.

  1. Ajouter une propriété projetId pour stocker l'id du projet et détecter si nous sommes en mode édition au création.
    export class ProjetCreer {
    projetForm = new FormBuilder().group({
    nom: ['', [Validators.required, Validators.minLength(3)]],
    description: [''],
    }, {
    updateOn : 'blur'
    });

    protected projetId: number | null = null;
  2. Implémenter OnInit sur le composant
    export class ProjetCreer implements OnInit {
    projetForm = new FormBuilder().group({
    nom: ['', [Validators.required, Validators.minLength(3)]],
    description: [''],
    }, {
    updateOn : 'blur'
    });

    protected projetId: number | null = null;

    get nom() {
    return this.projetForm.get('nom');
    }

    get description() {
    return this.projetForm.get('description')
    }

    constructor(private projetService: ProjetService,
    private router: Router) { }

    ngOnInit(): void {
    }
  3. Injecter la route active via ActivatedRoute
    constructor(private projetService: ProjetService,
    private router: Router,
    private route: ActivatedRoute) { }
  4. Récupérer l'id lors de l'initialisation du composant
    ngOnInit(): void {
    const id = this.route.snapshot.paramMap.get('id');
    if(id) {
    this.projetId = +id;
    }
    }
  5. Charger le projet si on a bel et bien un identifiant!
    async ngOnInit(): Promise<void> {
    const id = this.route.snapshot.paramMap.get('id');
    if(id) {
    this.projetId = +id;
    await this.chargerProjet()
    }
    }

    private async chargerProjet() {
    if(this.projetId) {
    const projet = await this.projetService.obtenir(this.projetId)
    }
    }
  6. Vous pouvez regarder dans l'onglet réseau de votre navigateur, vous devriez avoir une requête d'API lors du chargement de la page en mode édition. img

Préremplir le formulaire

Maintenant, remplissons le formulaire avec les données reçues. Pour cela, il existe une fonction patchValue sur le formulaire.

private async chargerProjet() {
if(this.projetId) {
const projet = await this.projetService.obtenir(this.projetId)
this.projetForm.patchValue({
nom: projet.nom,
description: projet.description
})
}
}
info

patchValue permet d'assigner des valeurs au formulaire via un objet. Le nom des propriétés doivent correspondre au nom des champs du formulaire.

Essayez de charger le formulaire de modification, vous devriez avoir les données du projet à modifier! 🎉

Mode édition vs. mode création

Il nous faut une façon de faire la distinction entre le mode édition et le mode création. En effet, le titre de la page doit être différent, le texte des boutons, en plus de l'action submit.

  1. Ajouter une valeur booléenne estModeEdition au composant avec false comme valeur par défaut.
    export class ProjetCreer implements OnInit {
    projetForm = new FormBuilder().group({
    nom: ['', [Validators.required, Validators.minLength(3)]],
    description: [''],
    }, {
    updateOn : 'blur'
    });

    protected projetId: number | null = null;
    protected estModeEdition: boolean = false;
  2. Assignez une valeur de true au chargement si un id est présent au niveau de la route.
    async ngOnInit(): Promise<void> {
    const id = this.route.snapshot.paramMap.get('id');
    if(id) {
    this.projetId = +id;
    this.estModeEdition = true;
    await this.chargerProjet()
    }
    }
  3. Modifier le titre de la page en mode édition
    @Component({
    selector: 'app-projet-creer',
    imports: [
    ReactiveFormsModule
    ],
    template: `
    <div class="row">
    <div class="col-lg-6 offset-lg-3">
    <h1>{{ estModeEdition ? 'Modifier le projet' : 'Créer un nouveau projet' }}</h1>

Nous avons une bonne ébauche de page réutilisant le même formulaire que la création, mais pour la modification!