Typed forms in Angular — why should we use them in everyday life?
Our application used Angular (v13) and one page of this application contains input. This application is about books — so the input is search (with autocomplete feature).
Data are fetched via two different APIs: a) one search by ISBN and b) and one using full-text search in book text data.
When the user navigates to this page, the URL always contains (in the query part) the value to search — this is used as a default value to fetch data after the page is open (so the user always sees data).
We were happy with the code. But there was one line which has a little bit magical, :
switchMap((searchedString: string | undefined) => {
- We are sure that “searchedString” is a string. But still, we must “force” this type.
- In our case, this variable will be always “defined” (e.g. have to value — we ensure this by other means). But still, we need to check for nullability.
These two assumptions (type/nullability) are “more our wishes than reality checked already during compile”.
Migration to v14
So one day we ran migration to Angular v14. One of our migration scripts converted all our “FormControll-s” to “UntypedFormControl”.
Well, everything works … fine. And than we read more about new typed forms https://angular.io/guide/typed-forms.
Type in FormControll
After reading of documentation (and examples), we realized that we can force the “string” type to form (see line 2).
Now “switchMap” operator already knows that “searchedString” is “string | undefined”.
But it cannot be null!
We know that the input will always contain some value — even after we open the page! So we use the new property “notNullable” of FormControl.
From this moment “searchedString” is always “not nullable” — we can safely use the “length” method. And all of this is to check during compilation.
Benefits?
- Introduced types to forms — improved possible bug detection during compile
- We simplified the code (removed obvious checks)
- improve IDE autocomplete
… thanks Angular team for this awesome feature!
Some ideas?
We are using OpenApi specification with interfaces generator:
@openapitools/openapi-generator-cli
- If we now add types to form, can we avoid the re-input of form data to the interface created with the generator?
- If the OpenApi definition changes (yes, our Backend colleagues somehow forgot to mention this …) — can we already detect problems during compilation?
And what about Template-Driven Forms?
If we would use Template-Driven forms (which we think is the preferred way) — we could not setup types (and nullability) for form elements defined in the template — because it would not be required.
The whole setup of “searchForm” (via FormControl) would be defined in HTML (under the hood FormControl would be used to define and control input — but that would be done by the Angular framework).
No FormBuilder, No FormControl, No FormGroup, … just HTML and custom methods to handle special events (on change of input, …). Model set to HTML would be defined via interface — there would be our strict types — and those interfaces are created/generated always (no matter which approach is followed).
We recommend watching “Prefer Template-Driven Forms” by Ward Bell.
With both approaches (Template-Driven forms or Reactive Forms) we could achieve the same result — interactive forms with full control, fully covered by tests.
- Do you think that Template-Driven forms are better? What are the benefits?
- Could Template-Driven forms reduce the time to implement forms? If yes, would you lose quality in your code or improve it?
- Could Template-Driven forms really simplify your code and reduce the number of required tests?
… feel free to leave a comment.
Thanks to Marek Vodicka for help with this article!
Typed forms in angular — why we should use them in real life? was originally published in ableneo Technology on Medium, where people are continuing the conversation by highlighting and responding to this story.