Signals: Why and when do we need them?

With the release of Angular 16, Signals are now available as a developer preview, which means we can start learning about Signals, testing them, and possibly adopting them.

The end goal of Signals is simple: Improve change detection in the Angular framework by removing the need for Zone.js. A signal-based application will be able to update individual views (a view is a sub-set of a component template — we create new views every time we use structural directives such as ngIf or ngFor) one by one instead of checking the entire component tree, enabling laser-focused updates of our DOM.

A secondary goal is to make Angular easier to learn by making RxJs less critical than before, which also applies to state management libraries such as NgRx or NgXs. In other words, we can rely less on operators, subjects, and the like.

Now that we covered the why, let’s talk about when to use signals. To get the full benefit of Signals in the long run, using them everywhere we have Observables or data bindings makes sense. I know this sounds like a lot of work, but that’s how we can get to a point where Angular can tell exactly which components must be updated when a value changes, no matter their location in the DOM tree.

An upcoming feature of Angular (v17 or later) will be signal-based components, where inputs, outputs, and even two-way bindings will be expressed as Signals:

I believe it makes sense to start using Signals as soon as possible. The base API is available in Angular 16 and is easy to learn. I already published a course that will be continuously updated as Signals evolve.

If you have any specific questions or concerns, feel free to send me your questions. I’ll be covering more about Signals as part of this newsletter.

Anti-pattern series: Calling a method in a template

If you’re calling a method/function in the HTML template of any of your components, try the following experiment: Add a console.log("here") inside that method.

Then, interact with your application by clicking around, entering information in a form, etc. What you’ll see in your console is something like this:

Why is this happening? Angular’s change detection runs every time an event occurs in the browser. Zone.js tells Angular that “something happened” when we interact with an Angular application. Then, Angular checks its component tree for updates. If you’re using methods in your HTML templates, the only way for Angular to see if the output of that method has changed is to… call it again.

As a result, using methods in your HTML templates is not recommended. Doing so can impact performance negatively. Instead, use bindings to class properties as follows:

Before:

After:

Note that if you need to call a method/function to perform some formatting, you should create a custom pipe. Pipes are designed to run only when their input data changes, which means they are optimized for best performance by default.

You can take a look at an example here on Stackblitz. I added a console.log("here") inside my custom pipe to showcase that it runs only once:

Angular Documentation Tricks

If you use Angular, you’re most likely familiar with the Angular website: https://angular.io.

But did you know that you access the documentation of a previous framework version by using the version number as a prefix, such as https://v14.angular.io?

Even better, you can get a glimpse of the future with https://next.angular.io or take a look at the current Release Candidate version: https://rc.angular.io.

Also, the header of the website has a different color whenever you’re not on the current version:

The red header is for the next version of Angular, the grey is for a past version, orange is for an RC, and blue is for the current one.

Sometimes though, the documentation does not answer all the questions we have, in which case we are just one click away from accessing the source code of any feature:

I used those tricks over and over again to prepare my course on Angular Signals. That’s how I could get a glimpse of the future and prepare several newsletter issues before the release of Angular 16.

RxJs concatWith operator

Our operator of the week is concatWith (the new name for concat since RxJS v7). This operator takes any number of Observables, subscribes to them one after the other, in sequence, and then returns the values emitted by the first Observable, then the second one, then the third one, etc.

Unlike forkJoin, which runs these Observables in parallel, concatWith runs them one after the other and waits for the completion of an Observable before subscribing to the next one.

As a result, concatWith can be used when:

  • We need to make multiple HTTP requests in a specific order, one after the other.
  • We need to combine user input with server data. For instance, we let the user select multiple filters in the UI, and when the user is done, we trigger an HTTP request to the server.

Angular 16 is now available!

Angular 16 is now available! You can watch a quick summary video from the Angular Team (in less than 7 minutes).

We’ve already covered quite a few of the new features in this newsletter:

Other notable features include:

  • Improved server-side rendering with non-destructive hydration: If you’re using Angular Universal, your app can now be refreshed on the client side without re-building the entire DOM (also a developer preview)
  • Angular CLI commands to convert your app to standalone components: ng generate @angular/core:standalone and to create a new standalone app with ng new --standalone
  • Experimental support of Jest (instead of Karma/Jasmine) for unit-testing
  • Support for Typescript 5.0.

The Angular team released a long blog post highlighting these features in more detail. I’ll cover more of these features individually over the following weeks, but for now, I’ll let you upgrade to the latest version with this tutorial.

NG16 Preview: Helpers to convert class guards to functional

As covered a few newsletters ago, Route guards are meant to be functions with Angular 15+. Angular 16 removes the support for class guards.

Does that mean we have to migrate our old class guards manually? Of course not! The Angular team has our back, and the Angular CLI will remove the deprecated interfaces automatically when upgrading to Angular 16 as follows:

Then, if you want to keep your guards as classes, you can do so using a helper function called mapToCanActivate:

Or you can, of course, decide to use a function instead:

Angular 16 Preview: Binding Router Information to Component Inputs

Passing parameters to routes is a frequent task with Angular. Before Angular 16, we had to inject the ActivatedRoute service and retrieve the parameters from that service using the snapshot or params properties.

With Angular 16, we can get those values automatically bound to the component inputs using the following router config:

If you’re using the RouterModule.forRoot() syntax, then enabling component input binding looks like this:

RouterModule.forRoot(routes, {bindToComponentInputs: true});Code language: JavaScript (javascript)

According to the documentation, this option can bind all route data with key-value pairs to component inputs: static or resolved route data, path parameters, matrix parameters, and query parameters.

For instance, assuming we have a URL parameter called id, if we enable the component input binding feature, then all we need in our component is an @Input decorator to receive that value:

What I like about this option is that our components do not need the ActivatedRoute service anymore, meaning they don’t have to be used just as routed components. Instead, they could be used in other scenarios where the id is passed as an HTML attribute, just like any other non-routed component. As a result, our components are more generic and not tied to a single use case.

Angular 16 Preview: Required Inputs

The @Input decorator plays an essential role in the Angular framework as such inputs for presentation components allow us to fine-tune application performance by using the onPush change detection strategy.

Earlier in this newsletter, we also talked about how inputs justified the existence of the ngOnInit lifecycle hook.

Inputs are about to become even better in Angular 16 with the addition of required inputs that would throw a compile-time error when an input for a component/directive is required but not set:

The syntax is easy to remember, too. Angular 16 is scheduled to be released this week, and I’ll be posting more new features of that new version all week long.

The main feature of v16 will be Angular Signals, so I just released a short video course to learn all you need to know about Angular Signals for just $9!

Angular 16 Preview: TakeUntilDestroyed

Angular 16 will be released next week, and this new version will be big. I will cover most of the new features of Angular 16 for the next few days.

One of the simple but handy features shipped with Angular 16 is a new operator for RxJs Observables: takeUntilDestroyed.

We have covered several techniques to automatically unsubscribe from Observables in this newsletter.

takeUntilDestroyed will make all of it easier than ever:

And that’s it! That one operator will take care of automatically unsubscribing from data$ when the component/pipe/directive using it is destroyed.

Signals will be the most significant addition to Angular 16 (as a developer preview – for now), and as a result, I’m about to launch a short course on Signals. If you’re interested in beta-testing that course (for free!), please respond to this email to let me know.

How to create your own two-way data binding with Angular?

If you’ve ever used [(ngModel)] with Angular, you know what two-way data binding is. The idea is to have a variable that works simultaneously as an Input and an Output.

In today’s post, we will see how to implement such a two-way data binding on our own so that we can use the [()] syntax on any of our component properties, such as message in the following code:

Before we get into this tutorial, I want to tease that signal-based components will have such two-way data bindings available out of the box with the following syntax – using a model() function instead of the @Input and @Output decorators we’re used to:

Note that the above feature will not be a part of the initial developer preview of Angular Signals coming out in less than two weeks with Angular 16. However, it might be available in developer preview in six months with Angular 17.

In any case, here is the link to my custom two-way data binding tutorial and a code example in action on Stackblitz.