Anti-pattern series: Using too many services

While services and dependency injection are good, just like many good things in life, they can be over-used and become somewhat of an anti-pattern.

Why? Because of how change detection works in Angular. Angular has two modes for change detection: The default mode and the onPush mode. onPush is an optimization that works if and only if you’re using input-driven components, also known as presentation components.

In other words, whenever you inject a service into a component, you prevent that component from using the optimized onPush change detection mode. This is one of the reasons best practices recommend sticking with container components (service-driven components tied to specific use cases) and presentation components (input-driven ones that can be used and reused as they’re not connected to any service – and any business logic).

The more presentation components you create, the more reusable your code is, and the more change detection can be improved. The next time you inject a service in a new component, think again: Could I pass that data as @Input(s) instead of injecting a service?

If so, congratulations: You just prevented your presentation component from falling into this anti-pattern.

Skeleton loaders with Angular

Skeleton loaders are grey-shaded shapes that indicate when a part of the screen is loading. Here is an example of skeleton loaders for Facebook:

ngx-skeleton-loader is a small component library that does just that. It gives us access to different skeleton loaders ready to be used in our applications:

What’s nice about that library is that we can customize different aspects of the skeletons, such as animations and colors. You can find some live examples here.

If you want to explore skeleton loaders for your application, feel free to look at my popular tutorial: How to use a skeleton loader with Angular?

The tutorial has several code examples that can be used as-is.

Two ways to update Angular Signals

Yesterday, I wrote about some best practices around exposing a Signal in our Angular applications. Let’s now take a look at the two different ways a Signal can be updated.

set()

The easiest way to update a Signal is the set() method. Nice and easy for basic data types such as strings or booleans:

update()

When the new value of a Signal depends on its previous value, update() is the best method to use. This is the ideal method for a counter, for instance:

Here is how to increment the counter based on its current value:

TL;DR

  • When you need to update a simple value (string, number, boolean), use set().
  • If that new value is based on the previous one, use update() instead of set()

Anti-pattern series: Not unsubscribing from Observables

We covered this in our newsletter before: Observables can cause memory leaks if we don’t unsubscribe from them.

Before Angular 16, there were a few different techniques available to unsubscribe automatically, the best of those being the async pipe (and yes, it’s possible to use the async pipe 100% of the time if you use the tricks highlighted here – no excuses).

With Angular 16, things are even better, as you can use the new takeUntilDestroyed operator as follows:

But here’s my million-dollar tip for today: Instead of using takeUntilDestroyed in your components, use it in the services that expose such Observables:

That way, whether you use an async pipe or not, your components are covered. That’s one of the nice things about Observables: We can change them whenever and wherever we want using pipe(), including in our services – so that all subscribers benefit from that change downstream.

Angular at Google I/O

This a very short post today as I spent most of my day at Google I/O, the annual conference where Google announces all sorts of updates ranging from AI to Android to Web, including Angular.

The Angular team had a few talks on Angular 16, all of which are now available on YouTube so that you can watch them too:

They also published a list of shorter videos (2 to 6 minutes) on Angular 16.

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.

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: