Angular 19 released next week!

This week, we get back to the new format of the newsletter. I’m posting a few essential articles to revisit, updates to know about, and one question to ponder:

Three short articles to revisit:

  • If you subscribe to Observables within another subscription, you’ll want to read this as it’s an anti-pattern. The solution is to use the switchMap operator or another equivalent, such as mergeMap.

Two Angular updates:

One question to think about:

Do your prefer Template driven forms or reactive? What about none of that? Have you ever considered that option?

RxJs tips and new resource API

In the new format of this weekly newsletter, I’m posting a few essential articles to revisit, updates to know about, and one question to ponder this week:

Three short articles to revisit:

If you haven’t adopted the takeUntilDestroyed operator, read this short tutorial about it. It’s even better than using the async pipe with @let or other automated unsubscription techniques.

Two updates to know about:

One question to think about:

Do you always unsubscribe from RxJs Observables? If you don’t, here are a few reasons why you should do it. Then refer to my 3 short articles above to see how you could do it both easily and consistently.

How to use toSignal() outside of an injection context?

If you’ve ever tried to convert an Observable into a Signal using the toSignal() function, you might have encountered the following error NG0203: toSignal() can only be used within an injection context:

This happens when you create an Observable outside of an injection context, which can happen if you want to download data when the user clicks on a button, for instance:

Can we make this work? Absolutely! The key is to access our injector and store it in a variable so we can pass it as a parameter to toSignal(). How to do that?

Interestingly enough, we can access our injector by… injecting it into our component:

Then, we pass it as an option to the toSignal() function:

And that’s it, problem solved! You can see the full code example on Stackblitz.

Code challenge #3 solution

Before I dive into the solution of code challenge #3, I wanted to mention that my next FREE workshop is scheduled for April 4th. It will be all about getting into RxJs from scratch, and you can register here. I’ll start from the basics and move on to more advanced topics, such as subjects and operators, and you’ll be able to ask me questions as we go through the content and exercises together.

As always, it’s a free workshop, but your coffee donations are always welcome.

Let’s get into our code challenge solution. The goal was to “connect” two different dropdowns so that the selection of the first dropdown (a continent) would update the contents of the second dropdown (a list of countries for that continent):

The challenge is that countries depend on two different Observable data sources:

  1. An HTTP request to an API to get the list of all countries in the world
  2. The currently selected continent (a reactive form select dropdown)

In other words, we start with the following code:

Our goal is to combine data from both Observables into one result. Ideally, such a result would be updated whenever any of the Observable sources are updated (e.g., a new continent is selected by the user, or a new list of countries is available from the API).

As a result, we can use the withLatestFrom operator to make that “connection” between our two Observables:

Such an operator returns an array of all the latest values of our source Observables in the order in which they were declared. As a result, we can use the map operator to receive that array and turn it into something different:

Inside that operator, we decide to return a new array. The continent remains the same, and we filter the list of countries based on that continent:

FInally, we can use tap to run some side effects. In our case, we update the list of countries used by the dropdown, and we set the country dropdown value to the first country of that list to ensure that a country from a previous continent doesn’t remain selected:

And that’s it! You can see that code in action on Stackblitz here.

A few of you sent me their own solutions to the challenge, and a recurring theme was that most of you didn’t “connect” the Observables and just assumed that the list of countries would already be downloaded and available by the time the user selected a continent. Something along those lines, where this.countries would be received from the API before that code runs:

While the above code would work most of the time, if a user selects a continent before this.countries is defined, an error would be thrown and the corresponding subscription destroyed, which means the above code would not run anymore when the user selects a new value. As a result, using operators is safer.

Another trick in my solution is that I didn’t use any .subscribe in my code, which means I don’t have to unsubscribe, as I let the async pipe do so for me automatically:

That’s it for code challenge #3! Next week, I’ll send you updates from ng-conf in Salt Lake City. If you’re around, feel ree to come say hi!

Code challenge #3: RxJs Wizardry

It’s been a few months since our last code challenge, where the goal is to have you look at some code that isn’t working and make you improve your Angular skills along the way.

In this code challenge #3, we have two select dropdowns that have to work together so that when we select a continent, we can only see countries from that continent in the second dropdown. The current code isn’t working – Argentina isn’t in Europe, so this selection should not be possible:

You can fork that code from Stackblitz here. Feel free to email me your solution once you have one ready. I’ll send you a possible solution in next week’s newsletter.

In case you missed my previous code challenges, here they are, along with the link to their respective solutions:

ShareReplay Code Challenge #1 Solution

What was wrong with yesterday’s code example? Here it is as a reminder:

Since the developer used the shareReplay operator, the intent was to cache the result of the HTTP request so that we do not make that request repeatedly.

The problem is that if several components call the getData() method, they all get a brand new Observable since the method returns a new request every time, which defeats the purpose of using shareReplay.

How can we fix this? By creating the Observable once then sharing the results in subsequent calls to getData():

Here’s another way to do it, perhaps even more readable:

Why do these solutions work? DataService is a singleton, which means all components use the same instance of DataService. As a result, any property of DataService (such as cache$) is the same for all components that access it.

Another critical thing to note is that HTTP requests are cold observables, which means they only fire when a subscriber subscribes to them.

RxJs eslint plugin for Angular

Last month, I discussed eslint and how to use that tool to parse your code and receive feedback on best practices and possible improvements.

Today, I want to mention an eslint plugin explicitly written for RxJs with Angular: eslint-plugin-rxjs-angular.

This plugin adds three possible validation rules:

All rules are optional, and it doesn’t make sense to use all of them at once because these best practices are contradictory in the sense that the goal is for you to choose one of these three approaches and be 100% consistent with it:

  1. The first rule will enforce that you always use the async pipe in your components.
  2. The second rule doesn’t care about the async pipe but wants to ensure you unsubscribe on destroy.
  3. The third rule is the most specific, as it enforces that you always use a Subject with takeUntil to unsubscribe in your components.

I’d suggest using the first rule only because we covered before that the async pipe is the safest and most performant option. And remember that you can always use the async pipe. There are no excuses!

RxJs Websockets for 2-way communication

Earlier this year, I covered the different types of RxJs subjects. There is another kind of Subject that I haven’t touched on yet: WebSocketSubject.

What is a websocket?

It’s a mechanism to establish and maintain a two-way connection between a client and a server on the web. This means that with websockets you can:

  • Receive real-time updates from a server
  • Send real-time updates to a server

There are several different use cases for websockets, such as: Real-time chat applications, online gaming, stock trading, and IoT applications.

How to create a websocket with RxJs?

All we need is the webSocket function from RxJs:

Note that the protocol is ws and not http. The above example assumes that our server accepts Websocket connections on port 8000. You can find a small example of such server-side code written with Node.js here.

To receive data from a WebSocketSubject, all we have to do is subscribe to it:

And if we want to send data to the server, we use the .next() method, which behaves differently from the one in the other types of Subjects:

Now you know how RxJs provides a straightforward implementation for handling Websockets using a specific type of Subject.

RxJs Timer for recurring tasks

You’re probably familiar with setTimeout (to run some code after a given timeout) and setInterval (to run some code at a given time interval). Both are “native” Javascript functions and can be used with Angular.

That said, recurring code execution is asynchronous, and asynchronous work is often done with RxJs in Angular apps. As a result, let’s talk about a 100% RxJs way to replace setTimeout and setInterval.

The RxJS timer operator creates an observable that emits a value after a specified delay. The delay can be specified in milliseconds or as a Date object.

The following code creates an observable that emits a value (0) after one second:

If we want timer to emit immediately and then keep emitting at a given interval, we can do the following:

This would emit 0 immediately, then 1 five seconds later, 2 ten seconds later, etc. Most of the time, we don’t care about the emitted number. We want to turn that Observable into another one (like an HTTP request, for instance) using our good friend switchMap:

What’s the benefit of using timer in such scenarios? We get automatic unsubscriptions if we use the async pipe or the takeUntilDestroyed operator.

Here is a tutorial for a concrete example of how to do HTTP polling with Angular and the timer operator.

RxJs trick: Emitting from an Observable into a Subject

Using a Subject to emit data is something we do a lot in Angular applications, and more often than not, what we try to emit is the result of an HTTP request, such as:

While the above works perfectly well, it’s important to know that the subscribe method of an Observable takes either a function as a parameter (which is what I’ve done in the previous example) or an object that implements the Observer interface. We touched on that interface earlier to illustrate exciting things we could do with the tap operator.

The thing is that Subjects implement that interface, so we can simplify our earlier code into:

This isn’t just a syntax improvement, as writing less functions results in better overall Javascript performance. Less code to ship = less code to download = less code to interpret and store in memory for the browser = faster user experience. You can see a code example here on Stackblitz.