- Angular Gems by Vasileios Kagklis
- Posts
- Catching Up with Angular’s Latest Changes
Catching Up with Angular’s Latest Changes
Key highlights of Angular’s latest version releases.
The latest versions of Angular introduced many changes to the framework.
Some call it a renaissance. Others call it an attempt to simplify the framework for newbie developers and to reach a broader audience.
Regardless of how you call it, one thing is for sure — there’s a lot going on lately in Angular!
In this article, we will go through the most important changes that happened in the latest versions of Angular (v14 — v17 specifically).
Some of them are major, while others are minor. But each one of them comes to add to the new picture of the framework.
Let’s get started!
Enhanced inject function
Starting from Angular v14, we can use the inject()
function outside an injection context.
As you can imagine, this opens up many possibilities. Here is an example:
However, there is one limitation — the devil is in the details.
We can use inject()
outside an injection context, but we can only call it inside one (like say, a constructor
).
The use inside ngOnInit
will throw an error during runtime.
Oh, and one more thing: it usually makes testing harder!
That being said, use it at your discretion.
Standalone components
Angular v14 is also the version where standalone components made an entrance.
Basically, NgModule
became optional.
Creating standalone components, directives, or pipes is as simple as adding standalone: true
to the metadata of their decorator.
Using standalone components comes with several benefits, such as more tree-shakable routing and more fine-grained lazy loading.
That of course doesn’t mean one has to migrate everything to standalone. If it doesn’t make sense for a case, then don’t!
Functional guards, resolvers, and interceptors
Angular v14 introduced functional route guards.
Before this change, we needed to create a service class, implement the respective interface, and then of course implement its method(s).
This worked fine but required a lot of extra code (see 10 vs. 3 lines of code).
Functional guards are then used the same way as class-based guards.
After the success of functional guards, functional interceptors and resolvers were next. These were introduced in Angular v15.
By the way, the class-based implementations were deprecated in favor of the functional ones.
Required component inputs
Starting from Angular v16, we can declare inputs as required for components and directives.
This will give a compilation error if we don’t provide the required input.
Routing parameters to routed component inputs
Angular v16 has introduced another input-related feature, which enables the automatic binding of router information to a routed component’s inputs.
That information can be query parameters, required (or path) parameters, static data, and resolver data.
Conflicts are resolved with a predefined priority:
data (static or resolved)
required parameters
query parameters
To enable this feature, add withComponentInputBinding()
in the provideRouter()
.
Now, assuming that the URL ends with products/123?searchTerm=Laptop
, we can access directly this information in a component as component inputs:
The takeUntilDestroyed operator
Starting from Angular v16, a new operator has been introduced (developer preview) — the takeUntilDestroyed
pipeable operator.
According to the docs, the takeUntilDestroyed
operator:
[…] completes the Observable when the calling context (component, directive, service, etc.) is destroyed.
Unsubscribing just became a piece of cake! 🍰
However, the operator needs a destroyRef
.
In the previous snippet, we are using the operator inside the constructor.
A constructor is an injection context, so the operator can grab the destroyRef
it needs.
But, if we wanted to use it inside a function or a lifecycle hook, we would have to explicitly pass the destroyRef
.
New reactivity with signals
The biggest change in Angular v16 was the new reactive primitive, also known as signals (developer preview).
What are signals?
A signal is a wrapper around a value, which is capable of notifying interested consumers when that value changes.
Why the need for signals?
Signals will be used as a signaling mechanism for change detection and will replace Zone.js (at some point in the future).
Why replace Zone.js?
Because performance!
You can read our previous articles about Zone.js in Angular and Angular signals to learn more.
The end goal is to be able to build completely zone-less Angular applications. But we are not there yet!
Here is a cheat sheet to get you started.
New control flow and deferred block
Starting from Angular v17 — which at the time of this writing is not yet released — a new declarative control flow will be introduced.
This brings the functionality of NgIf
, NgFor
, and NgSwitch
into the framework itself.
Here is a quick preview of the new control flow.
Components, directives, etc. referenced within the @defer
block are loaded lazily.
In other words, deferred blocks are rendered asynchronously.
This includes all dependencies within the deferred block, like components, directives, and pipes used in those dependencies.
Conclusion
Well, don’t tell me I didn’t warn you! 😅
A lot has happened in Angular in the latest versions.
In this article, we talked about the hottest changes 🔥, such as standalone components, signals 🚦, the new control flow, and many more!
Thanks for reading.