The ControlErrors component defines two inputs: control—the name of the control declared with the ngControl directive (the value of the ngControl attribute)—and errors—the mapping between an error and an error message. They can be specified respectively by the control and the errors attributes of the control-errors element.

For instance, if we have control:

<input type="text" ngControl="foobar" required />

We can declare its associated control-errors component by using the following:

<control-errors control="foobar"
      [errors]="{
       'required': 'The value of foobar is required'
      }"></control-errors>

Inside of the currentError getter, in the preceding snippet, we need to do the following two things:

  • Find a reference to the component declared with the control attribute.
  • Return the error message associated with any of the errors that make the current control invalid.

Here is a snippet that implements this behavior:

@Component(…)
class ControlErrors {
  …
  get currentError() {
    let control = this.formDir.controls[this.control];
    let errorsMessages = [];
    if (control && control.touched) {
      errorsMessages = Object.keys(this.errors)
        .map(k => control.hasError(k) ? this.errors[k] : null)
        .filter(error => !!error);
    }
    return errorsMessages.pop();
  }
}

In the first line of the implementation of currentError, we get the target control by using the controls property of the injected form. It is of the type {[key: string]: AbstractControl}, where the key is the name of the control we’ve declared with the ngControl directive. Once we have a reference to the instance of the target control, we can check whether its status is touched (that is, whether it has been focused), and if it is, we can loop over all the errors within the errors property of the instance of ControlError. The map function will return an array with either an error message or a null value. The only thing left is to filter all the null values and get only the error messages. Once we get the error messages for each error, we will return the last one by popping it from the errorMessages array.



The hasError method of every control accepts as an argument an error message identifier, which is defined by the validator. For instance, in the preceding example where we defined the custom e-mail validator, we will return the following object literal when the input control has an invalid value: { 'invalidEmail': true }. If we apply the ControlErrors component to the e-mail control, its declaration should look as follows:

  <control-errors control="email"
    [errors]="{ 'invalidEmail': 'Invalid email address' }"/>