Advertisement
  1. Code
  2. Angular

Einführung in Formen in Angular 4: Reaktive Formen

by
Read Time:14 minsLanguages:
This post is part of a series called Introduction to Forms in Angular 4.
Introduction to Forms in Angular 4: Template-Driven Forms
Introduction to Forms in Angular 4: Writing Custom Form Validators

German (Deutsch) translation by Nikol Angelowa (you can also view the original English article)

Final product imageFinal product imageFinal product image
What You'll Be Creating

Das ist der zweite Teil der Reihe zur Einführung in Formulare in Angular 4. Im ersten Teil haben wir ein Formular mit dem vorlagengesteuerten Ansatz erstellt. Wir haben Anweisungen wie ngModel, ngModelGroup und ngForm verwendet, um die Formularelemente aufzuladen. In diesem Tutorial werden wir einen anderen Ansatz zum Erstellen von Formen verfolgen - den reaktiven Weg.

Reaktive Formen

Reaktive Formen verfolgen einen anderen Ansatz als die vorlagengesteuerten Formen. Hier erstellen und initialisieren wir die Formularsteuerungsobjekte in unserer Komponentenklasse. Sie sind Zwischenobjekte, die den Status des Formulars enthalten. Wir werden sie dann an die Formularsteuerelemente in der Vorlage binden.

Das Formularsteuerungsobjekt überwacht jede Änderung der Eingabesteuerungswerte und spiegelt sich sofort im Status des Objekts wider. Da die Komponente direkten Zugriff auf die Datenmodellstruktur hat, können alle Änderungen zwischen dem Datenmodell, dem Formularsteuerungsobjekt und den Eingabesteuerungswerten synchronisiert werden.

High level overview of Reactive forms using model-driven approachHigh level overview of Reactive forms using model-driven approachHigh level overview of Reactive forms using model-driven approach

Wenn wir ein Formular zum Aktualisieren des Benutzerprofils erstellen, ist das Datenmodell praktisch das vom Server abgerufene Benutzerobjekt. Konventionell wird dies häufig in der Benutzereigenschaft der Komponente(this.user) gespeichert. Das Formularsteuerungsobjekt oder das Formularmodell wird an die tatsächlichen Formularsteuerungselemente der Vorlage gebunden.

Beide Modelle sollten ähnliche Strukturen haben, auch wenn sie nicht identisch sind. Die Eingabewerte sollten jedoch nicht direkt in das Datenmodell fließen. Das Bild beschreibt, wie die Benutzereingabe aus der Vorlage zum Formularmodell gelangt.

Lassen Sie uns anfangen.

Voraussetzungen

Sie müssen Teil eins dieser Serie nicht gefolgt sein, damit Teil zwei Sinn ergibt. Wenn Sie noch keine Erfahrung mit Formularen in Angular haben, würde ich Ihnen dringend empfehlen, die vorlagengesteuerte Strategie durchzuarbeiten. Der Code für dieses Projekt ist in meinem GitHub-Repository verfügbar. Stellen Sie sicher, dass Sie sich im richtigen Zweig befinden, und laden Sie dann die Zip-Datei herunter oder klonen Sie alternativ das Repo, um das Formular in Aktion zu sehen.

Wenn Sie lieber von vorne beginnen möchten, stellen Sie sicher, dass Angular CLI installiert ist. Verwenden Sie den Befehl ng, um ein neues Projekt zu generieren.

Generieren Sie als Nächstes eine neue Komponente für die SignupForm oder erstellen Sie eine manuell.

Ersetzen Sie den Inhalt von app.component.html durch Folgendes:

Hier ist die Verzeichnisstruktur für das Verzeichnis src/. Ich habe einige nicht wesentliche Dateien entfernt, um die Dinge einfach zu halten.

Wie Sie sehen, wurde automatisch ein Verzeichnis für die SignupForm-Komponente erstellt. Dort wird der größte Teil unseres Codes abgelegt. Ich habe auch eine neue User.ts zum Speichern unseres Benutzermodells erstellt.

Die HTML-Vorlage

Bevor wir uns mit der eigentlichen Komponentenvorlage befassen, müssen wir eine abstrakte Vorstellung davon haben, was wir erstellen. Hier ist also die Formstruktur, die ich im Kopf habe. Das Anmeldeformular enthält mehrere Eingabefelder, ein Auswahlelement und ein Kontrollkästchen.

The HTML TemplateThe HTML TemplateThe HTML Template

Hier ist die HTML-Vorlage, die wir für unsere Registrierungsseite verwenden werden.

HTML-Vorlage

Die in der HTML-Vorlage verwendeten CSS-Klassen sind Teil der Bootstrap-Bibliothek, mit der die Dinge hübsch gemacht werden. Da dies kein Design-Tutorial ist, werde ich nicht viel über die CSS-Aspekte des Formulars sprechen, es sei denn, dies ist erforderlich.

Grundlegende Formulareinrichtung

Um ein Reactive-Formular zu erstellen, müssen Sie das ReactiveFormsModule aus @angular/forms importieren und dem Import-Array in app.module.ts hinzufügen.

app/app.module.ts

Erstellen Sie dann ein Benutzermodell für das Registrierungsformular. Wir können eine Klasse oder eine Schnittstelle zum Erstellen des Modells verwenden. In diesem Tutorial exportiere ich eine Klasse mit den folgenden Eigenschaften.

app/User.ts

Erstellen Sie nun eine Instanz des Benutzermodells in der SignupForm-Komponente.

app/signup-form/signup-form.component.ts

Für die Datei signup-form.component.html verwende ich dieselbe oben beschriebene HTML-Vorlage, jedoch mit geringfügigen Änderungen. Das Anmeldeformular enthält ein Auswahlfeld mit einer Liste von Optionen. Obwohl dies funktioniert, werden wir es auf Angular-Weise tun, indem wir die Liste mit der ngFor-Direktive durchlaufen.

app/signup-form/signup-form.component.html

Hinweis: Möglicherweise wird die Fehlermeldung Kein Anbieter für ControlContainer angezeigt. Der Fehler wird angezeigt, wenn eine Komponente ein <form> -Tag ohne formGroup-Direktive hat. Der Fehler verschwindet, sobald wir später im Lernprogramm eine FormGroup-Direktive hinzufügen.

Wir haben eine Komponente, ein Modell und eine Formularvorlage zur Hand. Was jetzt? Es ist Zeit, sich die Hände schmutzig zu machen und sich mit den APIs vertraut zu machen, die Sie zum Erstellen reaktiver Formulare benötigen. Dies umfasst FormControl und FormGroup.

Verfolgen des Status mithilfe von FormControl

Beim Erstellen von Formularen mit der Strategie für reaktive Formulare werden Sie nicht auf die Anweisungen ngModel und ngForm stoßen. Stattdessen verwenden wir die zugrunde liegende FormControl- und FormGroup-API.

Ein FormControl ist eine Anweisung zum Erstellen einer FormControl-Instanz, mit der Sie den Status eines bestimmten Formularelements und seinen Validierungsstatus verfolgen können. So funktioniert FormControl:

email ist jetzt eine FormControl-Instanz, und Sie können sie wie folgt an ein Eingabesteuerelement in Ihrer Vorlage binden:

Das Vorlagenformularelement ist jetzt an die FormControl-Instanz in der Komponente gebunden. Dies bedeutet, dass jede Änderung des Eingabesteuerungswerts am anderen Ende wiedergegeben wird.

Ein FormControl-Konstruktor akzeptiert drei Argumente - einen Anfangswert, ein Array von Synchronisierungsprüfern und ein Array von Asynchronprüfern - und wie Sie vielleicht vermutet haben, sind sie alle optional. Wir werden hier die ersten beiden Argumente behandeln.

Angular verfügt über eine begrenzte Anzahl integrierter Validatoren. Zu den gängigen Validator-Methoden gehören Validators.required, Validators.minLength, Validators.maxlength und Validators.pattern. Um sie zu verwenden, müssen Sie jedoch zuerst die Validator-API importieren.

Für unser Anmeldeformular haben wir mehrere Eingabesteuerungsfelder (für E-Mail und Passwort), ein Auswahlfeld und ein Kontrollkästchen. Wäre es nicht sinnvoller, alle diese FormControls unter einer einzigen Entität zu gruppieren, als einzelne FormControl-Objekte zu erstellen? Dies ist vorteilhaft, da wir jetzt den Wert und die Gültigkeit aller Sub-FormControl-Objekte an einem Ort verfolgen können. Dafür ist FormGroup da. Daher registrieren wir eine übergeordnete FormGroup mit mehreren untergeordneten FormControls.

Gruppieren Sie mehrere FormControls mit FormGroup

Um eine FormGroup hinzuzufügen, importieren Sie sie zuerst. Deklarieren Sie als Nächstes signupForm als Klasseneigenschaft und initialisieren Sie es wie folgt:

app/signup-form/signup-form.component.ts

Binden Sie das FormGroup-Modell wie folgt an das DOM:

app/signup-form/signup-form.component.html

[formGroup] = "signupForm" teilt Angular mit, dass Sie dieses Formular der in der Komponentenklasse deklarierten FormGroup zuordnen möchten. Wenn Angular formControlName = "email" sieht, sucht es in der übergeordneten FormGroup nach einer Instanz von FormControl mit dem Schlüsselwert email.

Aktualisieren Sie in ähnlicher Weise die anderen Formularelemente, indem Sie ein Attribut formControlName = "value" hinzufügen, wie wir es gerade hier getan haben.

Fügen Sie nach dem Formular-Tag Folgendes hinzu, um festzustellen, ob alles wie erwartet funktioniert:

app/signup-form/signup-form.component.html

Führen Sie die SignupForm-Eigenschaft durch die JsonPipe, um das Modell im Browser als JSON zu rendern. Dies ist hilfreich beim Debuggen und Protokollieren. Sie sollten eine JSON-Ausgabe wie diese sehen.

Form state and validty in Model-driven formsForm state and validty in Model-driven formsForm state and validty in Model-driven forms

Hier sind zwei Dinge zu beachten:

  1. Der JSON stimmt nicht genau mit der Struktur des zuvor erstellten Benutzermodells überein.
  2. Der signupForm.status zeigt an, dass der Status des Formulars UNGÜLTIG ist. Dies zeigt deutlich, dass die im Feld "E-Mail-Steuerung" Validators.required wie erwartet funktionieren.

Die Struktur des Formularmodells und des Datenmodells sollte übereinstimmen.

Um die hierarchische Struktur des Datenmodells zu erhalten, sollten wir eine verschachtelte FormGroup verwenden. Darüber hinaus ist es immer eine gute Idee, verwandte Formularelemente unter einer einzigen FormGroup zu haben.

Verschachtelte FormGroup

Erstellen Sie eine neue FormGroup für das Passwort.

app/signup-form/signup-form.component.ts

Nehmen Sie nun die folgenden Änderungen vor, um das neue Formularmodell mit dem DOM zu verbinden:

app/signup-form/signup-form.component.html

formGroupName = "password" führt die Bindung für die verschachtelte FormGroup durch. Die Struktur des Formularmodells entspricht nun unseren Anforderungen.

Als nächstes müssen wir die Formularsteuerelemente validieren.

Validieren des Formulars

Wir haben eine einfache Validierung für die E-Mail-Eingabesteuerung eingerichtet. Das reicht jedoch nicht aus. Hier finden Sie die gesamte Liste unserer Anforderungen an die Validierung.

  • Alle Formularsteuerelemente sind erforderlich.
  • Deaktivieren Sie die Schaltfläche "Senden", bis der Status des Formulars VALID ist.
  • Das E-Mail-Feld sollte ausschließlich eine E-Mail-ID enthalten.
  • Das Passwortfeld sollte eine Mindestlänge von 8 haben.
Validating the formValidating the formValidating the form

Der erste ist einfach. Fügen Sie allen FormControls im Formularmodell Validator.required hinzu.

app/signup-form/signup-form.component.ts

Deaktivieren Sie anschließend die Schaltfläche, während das Formular INVALID ist.

app/signup-form/signup-form.component.html

Um eine Einschränkung für E-Mails hinzuzufügen, können Sie entweder die Standard-Validators.email verwenden oder eine benutzerdefinierte Validators.pattern() erstellen, die reguläre Ausdrücke wie den folgenden angibt:

Verwenden Sie den minLength-Validator für die Kennwortfelder.

Das war's für die Validierung. Die Formularmodelllogik erscheint jedoch überladen und wiederholt. Lassen Sie uns das zuerst aufräumen.

Refactoring des Codes mit FormBuilder

Angular bietet Ihnen einen Syntaxzucker zum Erstellen neuer Instanzen von FormGroup und FormControl mit dem Namen FormBuilder. Die FormBuilder-API macht nichts Besonderes als das, was wir hier behandelt haben.

Es vereinfacht unseren Code und erleichtert das Erstellen eines Formulars für die Augen. Um einen FormBuilder zu erstellen, müssen Sie ihn in signup-form.component.ts importieren und den FormBuilder in den Konstruktor einfügen.

app/signup-form/signup-form.component.ts

Anstatt eine neue FormGroup() zu erstellen, verwenden wir this.fb.group, um ein Formular zu erstellen. Mit Ausnahme der Syntax bleibt alles andere gleich.

app/signup-form/signup-form.component.ts

Anzeigen von Validierungsfehlern

Zur Anzeige der Fehler verwende ich die bedingte Direktive ngIf für ein div-Element. Beginnen wir mit dem Eingabesteuerungsfeld für E-Mail:

Hier gibt es einige Probleme.

  1. Woher kam invalid und pristine?
  2. signupForm.controls.email.invalid ist zu lang und zu tief.
  3. Der Fehler sagt nicht explizit aus, warum er ungültig ist.

Um die erste Frage zu beantworten, verfügt jedes FormControl über bestimmte Eigenschaften wie invalidvalidpristinedirtytouched, und untouched. Wir können diese verwenden, um zu bestimmen, ob eine Fehlermeldung oder eine Warnung angezeigt werden soll oder nicht. Das folgende Bild beschreibt jede dieser Eigenschaften im Detail.

 FormControl Properties in Angular Reactive approach FormControl Properties in Angular Reactive approach FormControl Properties in Angular Reactive approach

Das div-Element mit dem *ngIf wird also nur gerendert, wenn die E-Mail ungültig ist. Der Benutzer wird jedoch mit Fehlern begrüßt, dass die Eingabefelder leer sind, noch bevor er die Möglichkeit hat, das Formular zu bearbeiten.

Um dieses Szenario zu vermeiden, haben wir die zweite Bedingung hinzugefügt. Der Fehler wird erst angezeigt, nachdem das Steuerelement besucht wurde.

Um die lange Kette von Methodennamen (signupForm.controls.email.invalid) loszuwerden, werde ich ein paar Shorthand-Getter-Methoden hinzufügen. Dies hält sie leichter zugänglich und kurz.

app/signup-form/signup-form.component.ts

Um den Fehler deutlicher zu machen, habe ich unten verschachtelte ngIf-Bedingungen hinzugefügt:

app/signup-form/signup-form.component.html

Wir verwenden email.errors, um alle möglichen Validierungsfehler zu überprüfen und sie dem Benutzer dann in Form von benutzerdefinierten Nachrichten wieder anzuzeigen. Gehen Sie nun genauso vor wie bei den anderen Formularelementen. Hier ist, wie ich die Validierung für die Passwörter und die Begriffe Eingabesteuerung codiert habe.

app/signup-form/signup-form.component.html

Senden Sie das Formular mit ngSubmit

Wir sind fast fertig mit dem Formular. Es fehlt die Übermittlungsfunktion, die wir jetzt implementieren werden.

Beim Senden des Formulars sollten die Werte des Formularmodells in die Benutzereigenschaft der Komponente einfließen.

app/signup-form/signup-form.component.ts

Letzte Demo

Hier ist die endgültige Version der Anwendung. Ich habe ein paar Bootstrap-Klassen hinzugefügt, um das Formular hübsch zu machen.

Verpacken

Wenn Sie diese Tutorial-Serie von Anfang an verfolgt haben, haben wir praktische Erfahrungen mit zwei gängigen Formularerstellungstechnologien in Angular gemacht. Die vorlagen- und modellgetriebenen Techniken sind zwei Möglichkeiten, um dasselbe zu erreichen. Persönlich bevorzuge ich die reaktiven Formen aus folgenden Gründen:

  • Die gesamte Formularvalidierungslogik befindet sich an einem einzigen Ort - innerhalb Ihrer Komponentenklasse. Dies ist weitaus produktiver als der Vorlagenansatz, bei dem die ngModel-Anweisungen über die Vorlage verteilt sind.
  • Im Gegensatz zu vorlagengesteuerten Formularen sind modellgesteuerte Formulare einfacher zu testen. Sie müssen nicht auf End-to-End-Testbibliotheken zurückgreifen, um Ihr Formular zu testen.
  • Die Validierungslogik befindet sich innerhalb der Komponentenklasse und nicht in der Vorlage.
  • Für ein Formular mit einer großen Anzahl von Formularelementen verfügt dieser Ansatz über FormBuilder, um die Erstellung von FormControl-Objekten zu vereinfachen.

Wir haben eines verpasst, und das ist das Schreiben eines Validators für die Nichtübereinstimmung des Passworts. Im letzten Teil der Serie werden wir alles behandeln, was Sie zum Erstellen benutzerdefinierter Validierungsfunktionen in Angular wissen müssen. Bleib bis dahin dran.

In der Zwischenzeit gibt es viele Frameworks und Bibliotheken, die Sie benutzen können. Auf dem Envato Market können Sie viele Artikel lesen, studieren und verwenden.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.