Creating a custom form field with validation using AngularJS 1.5 and TypeScript

The typical way to do field validation in AngularJS making use of the built in FormController would look something like the following:

In this sample, if the text input is edited and then left empty:

  • the form group will be marked as red
  • the warning message will be displayed
  • the Submit button will be disabled
An excellent tutorial on making use of the built-in form validation can be found here.

Of course, adding more fields, the html would start to a look a little bit “busy” with all the additional validation boiler plate. And since I am working with AngularJS 1.5, I decided to turn it into a form field component.

Some requirements

It took quite a few variations to get to the solution. I was trying to make a component that would fulfill these criteria:

  1. Not involve the use of two-way binding. Though it is still possible to make use of two-way binding with Angular components (“=”) it is not recommend in the AngularJS documentation. The main reason being that a child should not be changing the parent’s data.
  2. The validation of the field should be handled by the component and not rely on the ngModel $invalid and $pristine for setting an error class or displaying warning messages.
  3. The validity of the form field should be communicated to the parent form to prevent data from being submitted by the user if any of the fields are invalid.

The result makes for much cleaner HTML:

The Code

The TypeScript is as follows:

and here’s the HTML for the view:

How it works

Instead of passing the field value through a binding (which would require either two-way binding or one-way binding with an event output) I make use of the require functionality to inject ngModel:

require: {
model: "ngModel"
}

I am then able to interact with the ngModel controller to read and write the model value:

READ: self.value = self.model.$viewValue
WRITE: this.model.$setViewValue(this.value)

and to set validity:

this.model.$setValidity("required",false)

I made use of $onInit as this is run after the component has been rendered and the model is accessible and then implement a handler for $render as this is called whenever the model is changed.

Limitations

In the original “busy” HTML form field implementation, the addition of built-in validation is easy, one just has to add the relevant attributes. In my implementation that would require additional JavaScript and could become quite messy if one wanted to support turning on/off a variety of validations.

But since the whole concept of Single Responsibility Principle seems to be something that is being embraced by the Angular community I would consider making new components to support this. That would also go for other field types, perhaps even making use of the inheritance that’s possible with TypeScript.