© Excellent backgrounds/Shutterstock.com
Teil 3: Formulare und Validierung

Deklarativ oder imperativ?


Angular kommt mit zwei Ansätzen für die Verwaltung von Formularen. Während der deklarative Ansatz etwas einfacher zu nutzen ist, bietet der imperative mehr Freiheiten. Daneben unterstützt das SPA-Framework aus der Feder von Google auch das Einbinden von synchronen und asynchronen Validierungsregeln.

Eine Stärke von Angular ist seit jeher die Verwaltung von Formularen. Angular 2 bringt hierzu gleich zwei Ansätze: einen deklarativen und einen imperativen. Ersterer sieht vor, dass der Entwickler die benötigten Formulare zur Gänze über HTML-Markup beschreibt. Hierbei ist auch von Template-driven Forms die Rede. Entscheidet sich der Entwickler hingegen für den imperativen Ansatz, so beschreibt er das Formular zum größten Teil über einen Objektgraphen und bietet diesen über den Component-Controller an. Während der deklarative Ansatz in der Regel mit weniger Aufwand einhergeht, bietet die imperative Alternative dem Entwickler mehr Kontrolle.

Dieser Artikel geht auf beide Ansätze ein und beschreibt auch die Validierung von Eingaben. Dazu betrachte ich die Entwicklung eines Formulars zum Editieren von Flügen (Abb. 1). Der gesamte Quellcode findet sich unter [1].

steyer_angular2_1.tif_fmt1.jpgAbb. 1: Formular mit Validierungsfehler

Deklarative Formulare

Der Einsatz deklarativer Formulare ist vom Prinzip her einfach: Der Entwickler bindet lediglich Eingabesteuerelemente mittels ngModel und Two-Way Data Binding an die jeweiligen Eigenschaften:

<input class="form-control" [(ngModel)]="flug.abflugort">

Zusätzlich hat er die Möglichkeit, Validierungsregeln über Attribute anzugeben. Das nachfolgende Beispiel zeichnet auf diese Weise das Eingabefeld als Pflichtfeld mit mindestens drei Zeichen aus:

<input class="form-control" [(ngModel)]="flug.abflugort" required minlength="3">

Im Hintergrund erzeugt Angular einen Objekt­graphen, der das gesamte deklarative Formular beschreibt (Abb. 2). An der Spitze dieses baumförmigen Graphen findet sich ein Objekt vom Typ FormDirective. Es steht für das gesamte Formular und zeigt unter anderem an, ob es korrekt validiert (valid) oder verändert (dirty) wurde. Nur wenn sämtliche Felder des Formulars korrekt validiert wurden, sieht Angular das Formular als valide an. Wurde auch nur ein Feld verändert, sieht Angular das Formular hingegen als verändert an.

Der Objektgraph enthält pro Eingabefeld ebenfalls ein Objekt. Diese lassen sich über die Auflistung Controls der FormDirective erreichen. Sie spiegeln den Zustand der einzelnen Eingabefelder wider und geben ebenfalls Auskunft über den Ausgang der Validierung (valid) sowie darüber, ob das Feld einer Änderung unterlag (dirty).

steyer_angular2_2.tif_fmt1.jpgAbb. 2: Objektgraph zur Beschreibung eines Formulars

Um eine Referenz auf diese Objekte zu erhalten, führt der Entwickler ein so genanntes Handle für das Formular ein. Dabei handelt es sich um eine Templatevariable innerhalb eines HTML-Elements, die auf eine hinter diesem Element stehende Direktive oder Komponente verweist. Ein Beispiel dafür findet sich in Listing 1. Es deklariert für das form-Element ein Handle f. Im Zug der Deklaration ist dem Handle eine Raute (#) voranzustellen. Diese ist bei weiterer Nutzung des Handles nicht mehr anzuführen.

Da hinter einem HTML-Element neben einer Komponente mehrere Direktiven stehen können, weist das betrachtete Beispiel zu #f den Wert ngForm zu. Damit gibt es an, dass die vorhin erwähnte FormsDirective zu f zuzuweisen ist. Dies funktioniert, da das Angular-Team die FormsDirective unter diesem Kürzel veröffentlicht.

Ein input-Element bindet das Beispiel an die Eigenschaft flug.abflugort, die sich im Component-Controller befindet (hier nicht abgebildet). Es weist die Validierungsattribute required und minlength auf. Daneben gibt das Attribut name=name an, dass dieses Eingabeelement im Objektgraphen durch ein Objekt mit dem Namen abflugort zu repräsentieren ist. Somit kann der Entwickler darauf über die FormsDirective mit f.controls.abflugort zugreifen. Da bei der deklarativen Vorgehensweise Angular den Objektgraphen erst nach der initialen Datenbindung erzeugt, sollte zusätzlich der Safe-Access-Operator (Elvis-Operator) zum Einsatz kommen: f?.controls?.abflugort. Das dem Punkt vorangestellte Fragezeichen bewirkt, dass Angular den gesamten Ausdruck als null auswertet, wenn der Teil links davon null ist. Auf diese Weise verhindert es die Navigation über null hinweg, was Angular 2 im Gegensatz zu seinem Vorgänger mit einer entsprechenden Exception abmahnt.

Das Beispiel prüft mittels *ngIf und der Eigenschaft valid, ob für den Abflugort mindestens ein Validierungsfehler vorliegt. In diesem Fall gibt es eine Fehlermeldung aus. Zusätzlich prüft es, welcher Validierungsfehler vorliegt. Dazu kommt die Methode hasError zum Einsatz. Auf diese Weise gibt das Beispiel eine zusätzliche, zu den aufgetretenen Fehlern passende Information aus.

Am Ende des Beispiels befindet sich auch eine Schaltfläche. Die Bindung an das Attribut disabled bewirkt, dass Angular sie beim Vorliegen von Validierungsfehlern deaktiviert.

Listing 1: Handle einführen

<form #f="ngForm"> <div class="form-group"> <label>Von:</label> <input class="form-control" [(ngModel)]="flug.abflugort" required minlength="3" name="abflugort" /> <div *ngIf="!f?.controls?.abflugort?.valid"> Validierungsfehler! </div> <div *ngIf="f?.controls?.abflugort?.hasError('required')"> Pflichtfeld! </div> <div *ngIf="f?.controls?.abflugort?.hasError('minlength')"> Zu Kurz! </div> </div> [....

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang