Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Formulare und Validierung in Angular

Formulare und Validierung in Angular

Slides from my talk at Angular Days, Oct 2017 in Berlin

Manfred Steyer

October 11, 2017
Tweet

More Decks by Manfred Steyer

Other Decks in Programming

Transcript

  1. Über mich … • Manfred Steyer • SOFTWAREarchitekt.at • Trainer

    & Consultant • Focus: Angular • Google Developer Expert (GDE) Page ▪ 2 Manfred Steyer
  2. Ansätze in Angular • ngModel im Template • Angular erzeugt

    Objektgraph für Formular • FormsModule Template- getrieben • Anwendung erzeugt Objektgraph • Mehr Kontrolle • ReactiveFormsModule Reaktiv • Angular generiert Formular für Datenmodell • An Community übergeben Daten- getrieben
  3. Template-getriebene Formulare Page ▪ 7 export class FlugSuchenComponent { von:

    string; nach: string; constructor(flugService: FlugService) { von = 'Graz'; nach = 'Hamburg'; } }
  4. View Page ▪ 8 <form> <input type="text" name="von" [(ngModel)]="von" required

    minlength="3"> […] </form> NgForm valid, dirty, … Control valid, dirty, … controls { } von
  5. View Page ▪ 9 <form #f="ngForm"> <input type="text" name="von" [(ngModel)]="von"

    required minlength="3"> […] </form> NgForm valid, dirty, … Control valid, dirty, … controls { } von
  6. View Page ▪ 10 <form #f="ngForm"> <input type="text" name="von" [(ngModel)]="von"

    required minlength="3"> <div *ngIf="!f.controls['von'].valid"> …Error… </div> </form> NgForm valid, dirty, … Control valid, dirty, … controls { } von
  7. View Page ▪ 11 <form #f="ngForm"> <input type="text" name="von" [(ngModel)]="von"

    required minlength="3"> <div *ngIf="!f?.controls['von']?.valid"> …Error… </div> </form> NgForm valid, dirty, … Control valid, dirty, … controls { } von
  8. View Page ▪ 12 <form #f="ngForm"> <input type="text" name="von" [(ngModel)]="von"

    required minlength="3"> <div *ngIf="!f?.controls['von']?.valid"> …Error… </div> <div *ngIf="f?.controls['von'].hasError('required')"> …Error… </div> </form> NgForm valid, dirty, … FormControl valid, dirty, … controls { } von
  9. Direktiven • Fügen Verhalten zur Seite hinzu • Beispiel: ngModel,

    ngClass, ngIf, ngFor • Kein Template im Gegensatz zu Komponenten Page ▪ 15
  10. Validierungs-Direktive Page ▪ 17 @Directive({ selector: 'input[ort]' }) export class

    OrtValidatorDirective implements Validator { validate(c: AbstractControl): any { let value = c.value; […] if (…) return { ort: true }; return {}; // Kein Fehler } }
  11. Validierungs-Direktive Page ▪ 18 @Directive({ selector: 'input[ort]', providers: [{ provide:

    NG_VALIDATORS, useExisting: OrtValidatorDirective, multi: true}] }) export class OrtValidatorDirective implements Validator { validate(c: AbstractControl): any { let value = c.value; […] if (…) return { ort: true }; return {}; // Kein Fehler } } .hasError(‘ort’)
  12. Attribute berücksichtigen Page ▪ 22 @Directive({ selector: 'input[ort]', providers: [{

    provide: NG_VALIDATORS, useExisting: OrtValidatorDirective, multi: true }] }) export class OrtValidatorDirective implements Validator { @Input() ort: string; validate(c: AbstractControl): any { […] } }
  13. Attribute berücksichtigen Page ▪ 23 @Directive({ selector: 'input[ort]', providers: [{

    provide: NG_VALIDATORS, useExisting: OrtValidatorDirective, multi: true }] }) export class OrtValidatorDirective implements Validator { @Input() ort: string; @Input() strategy: string; validate(c: AbstractControl): any { […] } }
  14. Multi-Field-Validatoren @Directive({ selector: 'form[roundTrip]', providers: [ … ] }) export

    class RoundTripValidatorDirective implements Validator { validate(control: AbstractControl): any { […] } }
  15. Multi-Field-Validatoren export class RoundTripValidatorDirective implements Validator { validate(control: AbstractControl): any

    { let group = control as FormGroup; let from = group.controls['from']; let to = group.controls['to']; if (!from || !to) return { }; […] }
  16. Multi-Field-Validatoren export class RoundTripValidatorDirective implements Validator { validate(control: AbstractControl): any

    { let group = control as FormGroup; let from = group.controls['from']; let to = group.controls['to']; if (!from || !to) return { }; if (from.value === to.value) return { roundTrip: true }; return { }; } }
  17. Asynchrone Validierungs-Direktiven Page ▪ 30 @Directive({ selector: 'input[asyncCity]', providers: [

    … ] }) export class AsyncCityValidatorDirective { validate(control: AbstractControl): Observable<any> { […] } }
  18. Reaktive Formulare export class FlugSuchenComponent { form: FormGroup; constructor(…) {

    let fromControl = new FormControl('Graz'); let toControl = new FormControl('Hamburg'); this.form = new FormGroup({ from: fromControl, to: toControl}); […] } }
  19. Reaktive Formulare export class FlugSuchenComponent { form: FormGroup; constructor(…) {

    let fromControl = new FormControl('Graz'); let toControl = new FormControl('Hamburg'); this.form = new FormGroup({ from: fromControl, to: toControl}); fromControl.validator = Validators.require; […] } }
  20. Reaktive Formulare export class FlugSuchenComponent { form: FormGroup; constructor(…) {

    let fromControl = new FormControl('Graz'); let toControl = new FormControl('Hamburg'); this.form = new FormGroup({ from: fromControl, to: toControl}); fromControl.validator = Validators.require; fromControl.asyncValidator = […]; […] } }
  21. Reaktive Formulare export class FlugSuchenComponent { form: FormGroup; constructor(…) {

    let fromControl = new FormControl('Graz'); let toControl = new FormControl('Hamburg'); this.form = new FormGroup({ from: fromControl, to: toControl}); fromControl.validator = Validators.compose([Validators.require, Validators.minLength(3)]); fromControl.asyncValidator = Validators.composeAsync([ … ]); […] } }
  22. FormBuilder export class FlugSuchenComponent { form: FormGroup; constructor(fb: FormBuilder, …)

    { this.form = fb.group({ von: ['Graz', Validators.required], nach: ['Hamburg', Validators.required] }); […] } }
  23. FormBuilder export class FlugSuchenComponent { form: FormGroup; constructor(fb: FormBuilder, …)

    { this.form = fb.group({ von: ['Graz', [Validators.required, Validators.minLength(3)] ], nach: ['Hamburg', Validators.required] }); […] } }
  24. FormBuilder export class FlugSuchenComponent { form: FormGroup; constructor(fb: FormBuilder, …)

    { this.form = fb.group({ von: ['Graz', [Validators.required, Validators.minLength(3)], [ /* asyncValidator */ ] ], nach: ['Hamburg', Validators.required] }); […] } }
  25. API this.form.valueChanges.subscribe(change => { console.debug('formular hat sich geändert', change); });

    this.form.controls['from'].valueChanges.subscribe(change => { console.debug('from hat sich geändert', change); }); let fromValue = this.form.controls['from'].value; let toValue = this.form.controls['to'].value; let formValue = this.form.value;
  26. Reaktive Formulare Page ▪ 45 <form [formGroup]="form"> <input id="from" formControlName="von"

    type="text"> <div *ngIf="!form.controls.von.valid">…Error…</div> […] </form>
  27. Ein einfacher Validator export class CityValidators { static validate (c:

    AbstractControl): any { if (c.value == 'Graz' || c.value == 'Hamburg') { return { }; } return { city: true }; } […] }
  28. Parametrisierte Validatoren export class CityValidators { static validateWithParams(allowedCities: string[]) {

    return (c: AbstractControl): any => { if (allowedCities.indexOf(c.value) > -1) { return { } } return { city: true }; }; } […] }
  29. Validatoren anwenden this.form = fb.group({ von: [ 'Graz', [ CityValidators.validate,

    CityValidators.validateWithParams(['Graz', 'Hamburg']) ], [ /* asyncValidator */ ] ], nach: ['Hamburg', Validators.required] });