GEDOPLAN
Webprogrammierung

Angular, Validatoren

Webprogrammierung

Formulare sind der Kern vieler Businessanwendungen. Neben der Prüfung innerhalb des Backends ist es in aller Regel auch eine Anforderung den Benutzer bereits bei der Eingabe auf eventuelle Fehler hinzuweisen. Angular bietet hierfür ein Konzept, das auf Direktiven basiert.

Bildschirmfoto vom 2017-06-08 13:03:43

Die von Angular mitgelieferten Validatoren sind überschaubar:

  • required, Pflichtfeld
  • minlength, Mindestlänge
  • maxlength, Maximallänge
  • pattern, Regular-Expression

Die Verwendung dieser Validatoren ist denkbar einfach. Nachdem das “FormsModule” (import { FormsModule } from ‘@angular/forms’;) in unser Modul importiert wurde, können diese Validatoren mittels Direktive an unseren Eingabefeldern registriert werden. Der Zugriff auf eventuelle Fehler erfolgt über den Zugriff mittels Templatevariablen (‘ngForm’ für Formulare, ‘ngControlGroup’ für Gruppen, ‘ngModel’ für Eingabefelder) und z.B. mit der Verwendung der “valid” Eigenschaft.

<form #form="ngForm" (ngSubmit)="submit()" novalidate>
    <span *ngIf="!namefield.valid"> Pflichtfeld </span>
    <input name="name" type="text" class="form-control" required ngModel #namefield="ngModel">
    <button type="submit" [disabled]="!form.valid">submit</button>
</form>

Eigene Validatoren

Hierzu wird eine Direktive erstellt die mit Hilfe eine so genannten “Multi Providers” den bestehenden Validatoren (NG_VALIDATORS) hinzugefügt wird (multi=true). Die eigentliche Implementierung erfolgt in der “validate” Methode, die entweder null zurück liefert, wenn kein Fehlerfall besteht oder ein Objekt, welches weitere Informationen zur Anzeige bereit stellen kann. Neben einzelnen Feldern können so auch Felderübergreifende Prüfungen implementiert werden. Anstatt die Direktive auf einem einzelnen Feld ein zu setzen wird dann im Template eine FromGroup verwendet die dem Validator später übergeben wird. Hier das Beispiel eines solchen Validators der über zwei Felder hinweg prüft ob ein gültiger numerischer Bereich angegeben wurde. Hier sehen wir auch wie unser Validator mit Parametern konfiguriert werden kann, in diesem Fall benötigt er die Pfade zu den Form-Controls um diese aus der FormGroup zu erhalten.

app.component.html

<div ngModelGroup #range="ngModelGroup" appRangeValidator von-pfad="lvon" bis-pfad="lbis">
    <input name="lvon" type="text" ngModel>
    <input name="lbis" type="text" ngModel></div>
{{range?.errors | json}}

range-validator.directive.ts

import { Directive, Input } from '@angular/core';
import { NG_VALIDATORS, FormGroup } from '@angular/forms';

@Directive({
  selector: '[appRangeValidator]',
  providers: [
    {
      provide: NG_VALIDATORS, useExisting: RangeValidatorDirective, multi: true
    }
  ]
})
export class RangeValidatorDirective {

  @Input('von-pfad')
  path1: string;

  @Input('bis-pfad')
  path2: string;

  validate(element: FormGroup) {
    const [val1, val2] = [element.get(this.path1), element.get(this.path2)];

    if ([val1, val2].every(e => e && e.value && e.value !== '')) {
      if ([val1.value, val2.value].some(e => !/^\d+$/.test(e))) {
        return { 'invalid-error': { valid: false, message: 'Ungültige Eingabe' } };
      } else if (Number.parseInt(val1.value) > Number.parseInt(val2.value)) {
        return { 'range-error': { valid: false, message: 'Erste Zahl muß kleiner sein als die Zweite' } };
      }
    }

    return null;
  }

}

Asyncrone Validatoren

Neben dem gerade gezeigtem syncronen Validatore bietet Angular auch eine asycrone Möglichkeit Prüfungen durch zu führen, wenn die zu prüfenden Werte z.B. erst an eine Rest-Schnittstelle übertragen werden sollen. Der grundsätzliche Aufbau bleibt der gleiche, wir verwenden lediglich den Multi Provider “NG_ASYNC_VALIDATORS” bei der Registrierung und unsere “validate” Methode muss dann ein Promise oder Observable zurück liefern, das wiederrum “null” oder ein Objekt mit den Fehler informationen enthält

async-user-validator.direvtive.ts

import { Directive } from '@angular/core';
import { NG_ASYNC_VALIDATORS, AbstractControl } from '@angular/forms';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';

@Directive({
  selector: '[appAsyncUserValidator]',
  providers: [
    { provide: NG_ASYNC_VALIDATORS, useExisting: AsyncUserValidatorDirective, multi: true }
  ]
})
export class AsyncUserValidatorDirective {

  constructor(private http: Http) { }

  validate(element: AbstractControl) {
    if (element && element.value && element.value !== '') {
      return this.http
        .get('https://jsonplaceholder.typicode.com/users')
        .map(r => r.json())
        .first()
        .map((e: any[]) => e.some(ele => {
          return ele.id == element.value
        }))
        .map(e => e ? null : { 'usernot': 'Benutzer existiert nicht' });
    }

    return Observable.from([null]);
  }
}

Der Validator fragt eine Rest-Schnittstelle nach Userdaten ab die als Rückgabe ein Array mit Usern liefert (für diesen Fall zugegeben ein schlechtes Schnittstellen-Design). Wir wandeln die Response hier in ein JSON-Objekt um, lassen uns das erste Elemente ( das Array ) geben, prüfen ob mindestens einer der User die übergebene ID besitzt und basierend auf diesem true/false Ergebnis erzeugen wir bei Bedarf einen entsprechenden Fehler.

(In einer echten Anwendung gehört die Kommunikation mit der Rest-Schnittstelle selbstverständlich in einen separaten Service!)

Zugegeben die Validatoren die Angular mitliefert sind überschaubar. Aber dank Bordmittel sind individuelle Validatoren schnell implementiert und auf die eigenen Bedürfnisse anpassbar.

Wie immer. Alles. Live. In Farbe. Bei Github

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Bitte füllen Sie dieses Feld aus.
Bitte füllen Sie dieses Feld aus.
Bitte gib eine gültige E-Mail-Adresse ein.
Sie müssen den Bedingungen zustimmen, um fortzufahren.

Autor

Diesen Artikel teilen

LinkedIn
Xing

Gibt es noch Fragen?

Fragen beantworten wir sehr gerne! Schreibe uns einfach per Kontaktformular.

Kurse

weitere Blogbeiträge

IT-Training - GEDOPLAN
Jakarta EE (Java EE)

JPA + Rest, JSON-B in Action

“JSR 367” alias JSON-B soll es endlich richten: ein standardisiertes JSON-Binding, ähnlich der Verarbeitung von XML mit JAXB. Gerade bei…
IT-Training - GEDOPLAN
DevOps

Docker – “Build, Ship, and Run”

Problemstellung Ein großes Problem stellen beim Testen und Ausliefern von Software die leider häufig unterschiedlich konfigurierten Ablaufumgebungen dar. Die Entwicklerrechner,…

Work Life Balance. Jobs bei Gedoplan

We are looking for you!

Lust bei GEDOPLAN mitzuarbeiten? Wir suchen immer Verstärkung – egal ob Entwickler, Dozent, Trainerberater oder für unser IT-Marketing! Schau doch einfach mal auf unsere Jobseiten! Wir freuen uns auf Dich!

Work Life Balance. Jobs bei Gedoplan

We are looking for you!

Lust bei GEDOPLAN mitzuarbeiten? Wir suchen immer Verstärkung – egal ob Entwickler, Dozent, Trainerberater oder für unser IT-Marketing! Schau doch einfach mal auf unsere Jobseiten! Wir freuen uns auf Dich!