Master Angular 16 (a study guide)
Gergely Szerovay
Posted on May 5, 2023
The latest version of Angular was released this week. Minko Gechev summarizes the most important new features in his release announcement.
This study guide helps you learn the new version of Angular.
🎯Changes and new features
In this article, I list out the most important changes and new features, also share resources that will teach you how these new Angular features work:
- Signals
DestroyRef
takeUntilDestroyed
- Required inputs
- Bind Router information to component inputs
- Node.js v14 support has been removed
- TypeScript 5.0 Support
- Angular Compatibility Compiler (ngcc) has been removed
- Server Side Rendering: Non-destructive hydration + now the results of a request done on the server side can be reused on the client side
- Strict type checking for
ngTemplateOutlet
-
provideServiceWorker
function to register service workers in standalone applications - Experimental Jest support
Next to these features, Angular 16 has a new Vite + Esbuild based dev server.
Naturally, reading articles about the changes is a good idea, additionally,
- the official documentation, and
- the Angular’s changelogs
also provide great insights, you should check these out, too.
📌Signals
Official docs: Angular Signals
GitHub discussion: Angular Reactivity with Signals
RFC: RFC: Angular Signals
PR: feat(core): add Angular Signals to the public API
PR: Prototype of the RxJS interop layer for signals
PR: feat(core): Mark components for check if they read a Signal
A new primitive type called “Signal” has been introduced in Angular. It’s designed to store a value similar to a regular variable. When the Signal’s value changes, it notifies the interested consumers. Signals store both primitive data types and objects.
A “Computed Signal” derives its value from other Signals. To create a Computed Signal, we need to use the computed function and specify the derivation function.
In case we use the OnPush change detection in a component and it has a Signal in its template, Angular tracks the Signal as a dependency for the component and marks the component for check if the Signal’s value changes. In Angular 17 this will change, it will be possible to use Signal based per-component change detection without zone.js.
Pawel Kozlowski’s talk at the NgBe is a great introduction to Signals, what features are in Angular 16 and what’s expected in Angular 17:
Deborah Kurata wrote a detailed tutorial on Signals, she explained why we need Signals, what they are, and how to create, read and update them. She also demonstrates the concept of computed Signals and effects.
Manfred Steyer compares the current Zone.js based change detection with the new Signal based approach.
Stefan Haas explains how signal and RxJS interoperability works.
Tomas Trajan explains how Signals work using the push & pull concepts.
📌DestroyRef
Official docs: DestroyRef
Commit: feat(core): introduce concept of DestroyRef
DestroyRef
lets you set callbacks to run for any cleanup or destruction behavior.
Example:
@Component({
selector: 'component-1',
standalone: true,
template: ``,
})
class Component1 {
constructor(private destroyRef: DestroyRef) {
destroyRef.onDestroy(() => {
// run this cleanup code, when the component is destoryed
});
}
}
In his article, Netanel Basal shows an example for how to create a reusable logic that performs a cleanup task when a scope is destroyed.
📌takeUntilDestroyed
Commit: feat(core): implement takeUntilDestroyed in rxjs-interop
takeUntilDestroyed
completes an observable in case the calling component (or directive, service or pipe) is destroyed.
In the following example, when the component is created, it starts to show ‘Tick’ messages on the browser’s console, using a subscription to a 2 second interval()
. When the component is destroyed, it unsubscribes from the interval()
:
@Component({
selector: 'component-1',
standalone: true,
template: ``,
})
class Component1 {
constructor() {
interval(2000).pipe(takeUntilDestroyed()).subscribe(() => console.log('Tick'));
}
}
It’s also possible to pass a specific DestroyRef
as a parameter to takeUntilDestroyed
, so we can create reusable functions with subscriptions that unsubscribe when the context is destroyed:
@Component({
selector: 'component-1',
standalone: true,
template: ``,
})
class Component1 {
constructor(private destroyRef: DestroyRef) {
reusableTicks(destroyRef);
}
}
📌Required inputs
Official docs: Input
PR: feat(compiler): add support for compile-time required inputs
We can mark component- or directive inputs as required. The following example fails in compile time, as in the Component2
’s template we didn’t provide the required text
input:
@Component({
selector: 'component-1',
standalone: true,
template: ``,
})
class Component1 {
// ❗ this is a required input
@Input({ required: true }) text: string;
}
@Component({
selector: 'component-2',
standalone: true,
template: `
<component-1></component-1>
`,
imports: [Component1]
})
class Component2 {
constructor(private destroyRef: DestroyRef) {
destroyRef.onDestroy(() => {
// run this cleanup code, when the component is destoryed
});
}
}
📌Bind Router information to component inputs
Official docs: Router / Getting route information, withComponentInputBinding
PR: Feature to bind Router information to component inputs
This new feature simplifies the process of getting route information. Enea Jahollari explains how this new feature works by examples.
📌Node.js v14 support has been removed
Changelog entry: Node.js v14 support has been removed
Node.js v14 is planned to be End-of-Life on 2023–04–30. Angular will stop supporting Node.js v14 in Angular v16. Angular v16 will continue to officially support Node.js versions v16 and v18.
📌TypeScript 5
From Angular’s perspective, the two most important new features in Typescript 5 are:
- the decorators
- and the supporting of multiple configuration files in
tsconfig.json
‘s extends.
Decorators
TypeScript 5 supports a new version of the ECMAScript decorator proposal, referred to as ‘Standard decorators’.
Kevin Kreuzer explains us in his article, how these new decorators work.
Multiple configuration file support in tsconfig.json
‘s extends
For example, both strict
and noImplicitReturns
are enabled in the final tsconfig.json
in the following example:
// tsconfig-a.json
{
"compilerOptions": {
"strict": true
}
}
// tsconfig2-b.json
{
"compilerOptions": {
"noImplicitReturns": true
}
}
// tsconfig.json
{
"extends": ["./tsconfig-a.json", "./tsconfig-b.json"],
"files": [
"src/main.ts",
"src/polyfills.ts"
]
}
You can find more details of the new Typescript features in their official announcement.
📌Angular Compatibility Compiler (ngcc) has been removed
Changelog entry: Angular Compatibility Compiler (ngcc) has been removed
Angular 9 transitioned its rendering architecture from the “ View Engine” to “Ivy”. However, to support libraries that were still dependent on the “View Engine”, Angular Compatibility Compiler (ngcc) was created. In Angular 16, ngcc and all other codes related to the old “View Engine” have been removed, so “View Engine” libraries can no longer be used in v16+.
To learn more about “Ivy”, read Maria Korneeva‘s article about how “View Engine” and “Ivy” works and what is new in “Ivy”.
📌NgZone is configurable in bootstrapApplication
Official docs: provideZoneChangeDetection
PR: Add ability to configure NgZone in bootstrapApplication
There are two zone configuration related changes in Angular 16:
- We can provide a custom zone implementation in
bootstrapApplication
- NgZone now has two configurable options:
eventCoalescing
andrunCoalescing
, these options might help reduce the change detection cycles in your application.
class CustomZone extends NoopNgZone {}
bootstrapApplication(
StandaloneCmp, {
providers: [
// provide a custom zone implementation
{ provide: NgZone, useValue: new CustomZone() }
]
}
);
bootstrapApplication(
StandaloneCmp, {
providers: [
// enable eventCoalescing and runCoalescing
provideZoneChangeDetection({
eventCoalescing: true,
runCoalescing: true
})
]
});
📌Server Side Rendering improvements
Non-destructive hydration
PR: feat(platform-browser): add a public API function to enable non-destructive hydration
With non-destructive hydration, Angular has the capability of reusing pre-existing DOM structures on the client-side that were initially rendered by the server. This prevents the flicker that occurs when the page is rendered and ready for interaction by users.
The results of the request done on the server side can be reused on the client side
PR: feat(platform-browser): enable HTTP request caching when using provideClientHydration
To avoid the need of refetching the same data on the client side, requests made on the server side will be cached and accessible on the client side.
Jessica Janiuk summarized the current state and future of the server side rendering in her blog post.
📌Strict type checking for ngTemplateOutlet
PR: fix(common): strict type checking for ngtemplateoutlet
Previously, when we passed a context to ngTemplateOutlet, it was passed as an Object, so in the following example there was no compilation error:
interface Context1 {
prop: number;
}
@component({
standalone: true,
imports: [NgTemplateOutlet],
selector: 'person',
template: `
<ng-container
*ngTemplateOutlet="
myTemplateRef;
context: { prop: 1, missingProp: 2 }
"></ng-container>
`,
})
export class Component1 {
templateRef!: TemplateRef<Context1>;
}
Now in Angular 16 the code in the previous example fails with a compile time error, as missingProp
is not defined in Context1
. We can fix this by adding the missingProp
property to Context1
or add $any(…)
inside the template to preserve the previous behavior.
📌provideServiceWorker function to register service workers in standalone applications
Official docs: Service workers / provideServiceWorker
PR: feat(service-worker): add function to provide service worker
Previously to register a service worker in a standalone app, we had to use importProvidersFrom(ServiceWorkerModule.register(…))
.
provideServiceWorker is a new way to register service workers in standalone apps, usage example:
bootstrapApplication(AppComponent, {
providers: [
provideServiceWorker('my-service--worker.js')
],
});
📌Experimental Jest support
The Angular Team added initial experimental support for Jest in Angular 16. In Angular 17, they’ll replace the deprecated Karma test runner with the Web Test Runner.
➕ Have you seen any other resources I should add to this Angular 16 Study Guide? Please send it to me so that I can feature it in the article!
👨💻About the author
My name is Gergely Szerovay, I work as a frontend development chapter lead. Teaching (and learning) Angular is one of my passions. I consume content related to Angular on a daily basis — articles, podcasts, conference talks, you name it.
I created the Angular Addict Newsletter so that I can send you the best resources I come across each month. Whether you are a seasoned Angular Addict or a beginner, I got you covered.
Next to the newsletter, I also have a publication called — you guessed it — Angular Addicts. It is a collection of the resources I find most informative and interesting. Let me know if you would like to be included as a writer.
Let’s learn Angular together! Subscribe here 🔥
Follow me on Medium, Twitter or LinkedIn to learn more about Angular!
Posted on May 5, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
July 16, 2024