Reactive Forms
Custom Validators
In this exercise you will create a custom Validator which validates the entered city names against a hardcoded list of valid cities, but this time without using a Directive, but a function instead.
-
Implement all new reactive Validators inside the folder
shared/validators. -
Create a new file
city-validator.tsand implement a Validation functionvalidateCity()which uses anAbstractControlas input parameter and shall validate the provided city name by checking a list of valid cities.Show code
import {AbstractControl, ValidationErrors} from '@angular/forms'; export function validateCity(c: AbstractControl): ValidationErrors | null { const validCities: string[] = ['Vienna', 'Cologne', 'Bern']; if (c.value && validCities.indexOf(c.value) === -1) { return { city: { actualValue: c.value, validCities: validCities } }; } return null; } -
Open the file
flight-edit.component.tsand register the new Validation function for thefromFormControl.Show code
[…] import {validateCity} from '[…]'; @Component({ […] }) export class FlightEditComponent implements OnInit { […] getInitialEditForm(): FormGroup { return this.fb.group({ […] from: [ null, [ […], validateCity ] ], […] }); } } -
Open the file
flight-edit.component.htmland make sure whether and error forcitywas found. In case of an error show are message in your Component.Show code
[…] <div class="alert alert-danger" *ngIf="editForm.controls['from'].hasError('city')"> ...city... </div> […] -
Test your application.
Parameterized Validators
Extend the previously implemented Validator, so that it becomes parameterizable. A list of valid city names shall be provided as input parameter.
-
Open the file
city-validator.tsand extend the functionvalidateCity(). It shall usestring[]as input parameter and return a Validation function for later use.Show code
import { […], ValidatorFn } from '@angular/forms'; […] export function validateCity (validCities: string[]): ValidatorFn { return (c: AbstractControl) => { if (c.value && validCities.indexOf(c.value) === -1) { return { city: { actualValue: c.value, validCities: validCities } }; } return null; }; } -
Open the file
flight-edit.component.tsand change the way the function is used here. In the previous exercise we added a referance to thevaldiateCityfunction so that the Angular framework can use it for starting a validation process later. Now we need to call the outer function by setting the list of valid cities parameter and then the Angular framework can - again - access a function (the inner function that gets returned) to start aFormControlvalidation whenever it is necessary.Show code
[…] return this.fb.group({ […] from: [ null, [ […], validateCity(['Vienna', 'Berlin', 'Gleisdorf']) ] ], […] }); […] -
Test your application.
Multi-Field-Validators
Implement a Multi-Field-Validator. It shall check whether from and to have the same name. Implement it as exported function so that it can be used in Reactive Forms.
You can assign the reference to the Validator function directly to editForm.validator property.
ngOnInit(): void {
[…]
this.editForm.validator = validateRoundTrip;
[…]
}
Show code
import { AbstractControl, FormGroup, ValidationErrors } from '@angular/forms';
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
export function validateRoundTrip(control: AbstractControl): ValidationErrors | null {
const group = control as FormGroup;
const from = group.controls.from;
const to = group.controls.to;
if (!from || !to) {
return null;
}
if (from.value === to.value) {
return { roundTrip: true };
}
return null;
}
Bonus: Load a Flight *
Load a Flight with an ID of your choice represented as constant value and write it to the form by using the method editForm.patchValue().
In case you implemented Routing already you could receive the ID from the Routing Params and use it to load a specific Flight.
Bonus: Save a Flight *
Implement a save() method and a button in the Template to call this method. The FlightService shall be used to send the updated Flight to your API. You can access the current form value by using editForm.value.
- Use
HttpClient'spost()method and the URLhttp://www.angular.at/api/flightto create or update a Flight. - Use a Flight object as second argument of the
post()method. - To create a new Flight use the Flight's
idproperty set to0respectively use a specificidto update one.