Angular component practices

Angular is known to provide complete solutions out of the box. It gives developers all the tools alongside the guideline on how to create applications. Overall that makes it more strict than other solutions like React or Vue. In my opinion, Anulgar is still very flexible. It allows creating an application using different practices. Some of them are good for small projects others for larger ones. In this article, I would like to present some of the component practices for larger applications.
Motivation
The main idea behind these practices is:
Project basecode should look like it is written by one person.
In other words, practices goals are:
- Allow developers to focus on technical aspects - they don't have to think about nuances,
- I'm a big fan of TypeScript strict mode as it reduces the number of places where a developer can make a mistake- style guide should be compatible with strict mode,
- Focus on large enterprise-scale applications - some of the practices may look too complicated, but in larger projects, they are worth using.
1. Input
Inputs are one of the most commonly used methods of communication with a component.
Required inputs
The most important inputs are the ones that are required by the component in order for it to work. We need to be able to distinguish these inputs from the ones that are not needed. There are two techniques that will let us achieve it.
First of all, we need to specify the input name in the component selector:

This method changes the selector of the component. Now angular will not recognize the model
tag used alone without also specifying the text input
.
The problem that still exists is that TS strict mode doesn't allow declaring a variable without assigning a value to it, or adding to its type that it can also be undefined
. This practice focuses on reducing the number of null
or undefined
usages, so I prefer a different solution. To read more about TypeScript strict mode I recommend this article Bulletproof TypeScript - strict mode for Enterprise scale Applications.
The text input is required and it will always have a value, so we need to tell the TS compiler about it. To do it the best practice is to use the exclamation mark or non-null assertion operator.

Optional inputs
Some of the inputs are optional by the component, they are not required by it in order to work.
The best way to handle it is by assigning a value to the input:

For most of the cases, you can assign input with an empty value, like e.g. string property can be initialized with an empty string ''
.
You cannot always assign the default value for the input. In that case, use the ?
mark and make property optional:

Input practices
- Required inputs should be specified in the selector,
- Required inputs should be declared with an exclamation mark(non-null assertion),
- Optional inputs should be assigned with value,
- When the previous point is not possible not required inputs should be declared as optional with
?
mark.

Presented practice makes component inputs much more readable. You can tell right away which input is required and with is optional. A developer is able to use components more easily.
2. Outputs
Outputs allow for communication with the parent of the component.

Output practices
- Always initialize output variables on the declaration - assign value with
new EventEmitter()
, - Declare property as
readonly
so no one reassigns it with a new value, - Specify the type of
EventEmitter
.
3. Queries
The next practices concern view and content queries:
- @ViewChild,
- @ViewChildren,
- @ContentChild,
- @ContentChildren.
readonly
Queries are similar to inputs in a way that we don't set their values, the framework does it for us. For e.g. we only read a value of a @ViewChild
property. That is why we should declare properties as optional and readonly
:

type
One of the powerful features of queries is that you can specify the read property.

It can select different types of values. From ElementRef
and ViewContainerRef
to any provider defined in the components injector.
That is the way in order to always be sure what is the correct type of the variable you should specify the read
property:

Query practices
- declared as optional - they cannot be assigned at the start,
- always specify
readonly
- developer can only read the value of the query property. The framework's responsibility is to set its value, - always specify correct
read
type.

4. Selector
Angular components are always rendered in dom as custom elements. They have no built-in CSS styles. This is kind of uncomfortable for the developer, as you always have to remember to set the display property:

There is an interesting practice which I recommend using. You can specify the selector of the component as div[model]
which tells Angular that the ModelComponent
can be used only on the div
tag:

You can use this model component in the template:

You can specify any other tag in the selector. It doesn't have to be div
.
Style guide
If you are interested in checking more of these practices, I recommend visiting The Generic UI Angular Style Guide.
Final word
Some of the practices may look like overreacting. When I first saw it I immediately ask myself, will I ever make that kind of mistake. Will I ever assign a value to an input or a property connected to a ViewChild
? My answer is probably not. In my head, I already see the readonly
next to the input property, even though it is not here. But practices are not for me, they are for everyone who works with angular and want to make their application more readable and have fewer bugs. No matter their experience in the framework.