Asynchrone Form Validation mit Angular FormBuilder (und Ionic 2)

Feld Validierungen mit Angular FormBuilder sind einfach. Sie werden einfach bei der Feld-Definition angegeben, z.B. eine Minimal-Länge beim Passwort.

Die Validierung akzeptiert übrigens auch einen Array von Validators. Wie im Beispiel gezeigt, werden zwei Validators übergeben (required und minLength).

Die Validierung kann kann dann im UI verwendet werden.

 

Asynchrone Validierung

Nebst dieser klassischen, synchronen Validierung können auch asynchrone Validierungen gemacht gemacht werden. Gerade mit Angular, Ionic und Firebase, wo alles asynchrone mit Observables abläuft, wird man früher oder später dazu kommen. Allerdings habe ich nirgends ein richtiges Beispiel dazu gefunden. Alle Tutorials verwenden immer irgendwelche Observables mit mit setTimeout.

In meinem Beispiel musste ich bei der Benutzer-Registrierung die Email-Adresse prüfen, ob sie schon verwendet wurde. Ein klarer Fall für eine asynchrone Validierung. Der Validator wird als drittes Argument nach den synchronen Validators angegeben. 

Damit der asynchrone Validator auf die Instanz-Variablen zugreifen kann, wird die Methode mit .bind(this) verbunden.

Die einfachste Möglichkeit die Validierung asynchron durchzuführen, ist eine Promise zu verwenden.

userService.users$ ist in diesem Fall ein Firebase-Zugriff, es könnte aber genau so gut ein http-Aufruf mit JSON-Rückgabe sein.

 

Ausstehende Validierung

Wie weiss das UI nun, ob die asynchrone Validierung beendet ist? Angular liefert dazu bei asynchronen Validators den Status „pending“.

So lange übrigens eine Validierung aussteht, kann auch das ganze Form nicht valid sein. Das heisst, mann muss z.B. beim Submit-Button nicht noch extra auf „pending“ prüfen.

 

Wiederverwendbare Validators

Die Validierung in der gleichen Klasse zu definieren, wie die zu testenden Felder, geht so lange, wie die Validierung nicht mehrmals verwendet werden muss.

Typischerweise hat man für mehrfach verwendete Validatoren eine eigene Klasse, wie z.B. für Email-Adressen (wofür es erstaunlicherweise keinen Default-Validator in Angular gibt)

 

Der Client importiert dann den Validator und verwendet ihn wie einen Standard Validator

 

Wenn nun asynchrone Validators in einer eigenen Klasse definiert werden sollten, dann funktioniert der „.bind(this)“ Trick nicht mehr.

In diesem Fall müsste die Validator-Klasse die nötigen Services, wie z.B. oben der Firebase UserService selbst instanzieren.  Da alle Methoden aber typischerweise static sind, können die benötigen Services nicht wie gewohnt im Constructor injected werden. Deshalb nimmt man den ReflectiveInjector dazu.

 

 

 

 

Urs Verfasst von: