Vincent Barrault

Faire des formulaires réutilisables avec Angular

Faire des formulaires réutilisables avec Angular

Table des matières

Contexte

Dans les grosses applications avec beaucoup de pages et de formulaires, il est parfois nécessaire d'avoir des champs ou des groups de champs réutilisables dans différentes pages.

Par exemple, pour la création et l'édition d'une même entité, nous serions tentés de n'avoir qu'un seul formulaire pour les deux pages. Nous allons voir comment réaliser cela.

Création du composant de formulaire

import { Component, forwardRef } from '@angular/core';
import { ControlValueAccessor, FormControl, FormGroup, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validator, Validators } from '@angular/forms';

@Component({
    selector: 'app-user-form',
    template: `
        <form [formGroup]="form">
            <label>FirstName: <input formControlName="firstname" /></label>
            <label>LastName: <input formControlName="lastname" /></label>
        </form>
    `,
    providers: [
        { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => UserFormComponent), multi: true },
        { provide: NG_VALIDATORS, useExisting: forwardRef(() => UserFormComponent), multi: true }
    ]
})
export class UserFormComponent implements ControlValueAccessor, Validator {

    public form = new FormGroup({
        firstname: new FormControl('', [Validators.required]),
        lastname: new FormControl('', [Validators.required]),
    });

    public registerOnChange(fn: (value: any) => {}) {
        this.form.valueChanges.subscribe(fn);
    }

    public writeValue(value: any) {
        if (value) {
            this.form.patchValue(value);
        } else {
            this.form.reset();
        }
    }

    public registerOnTouched(_: () => {}) {}

    public validate(_: FormControl) {
        return this.form.valid ? null : { user: { valid: false } };
    }
}

En implémentant ControlValueAccessor et Validator, nous allons devoir implémenter des méthodes qui vont permettre au reactive form d'Angular de communiquer les valeurs et l'état de notre formulaire au formulaire parent.

Le composant app-user-form pourra donc s'utiliser comme un simple champs de formulaire, sauf qu'il s'agira d'un groupe de champs.

Utilisation dans une page

Par exemple, si nous voulons utiliser notre formulaire dans une page UserCreateComponent, nous devrons juste passer l'instance de notre formulaire à l'élément app-user-form, et ce dernier se chargera du reste.

./app/user-create/user-create.component.ts
import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';

@Component({
    selector: 'app-user-create',
    template: `
        <app-user-form [formControl]="form"></app-user-form>
        <button [disabled]="form.invalid" (click)="submit()">Submit</button>
    `
})
export class UserCreateComponent {
    public form = new FormControl();

    public submit(): void {
        console.log(this.form.value);
    }
}