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' }"/>