Local variables and the new block syntax

Earlier this year, I mentioned how the async pipe can become much more useful if we use a local variable instead of multiplying subscriptions to an Observable. In this example, we store the data we get from a subscription in the user variable:

While that syntax still works as is, you might want to use the new control flow syntax of Angular 17. Fortunately for us, it is possible to use local variables as well using the following syntax:

The only difference is the ; in the middle of the expression.

Using FormBuilder or FormControl?

When creating reactive forms with Angular, we have two options available. The most documented one is to inject the FormBuilder service and use it to generate your form’s structure:

FormBuilder makes perfect sense for forms that contain lots of elements. This service gives us methods that are factories for the following syntax, which is a lot more verbose:

Now, if you have a simple form with just one or two form controls, you don’t need FormBuilder. Declaring your FormControl “manually” is actually more manageable that way:

You can find an example of a single FormControl with custom validation here on Stackblitz.

How to cache HTTP requests with a service worker?

In the past few weeks, we’ve talked about how to cache data with HTTP interceptors, with Subjects, and with shareReplay.

While all these options work, they are intrusive and need additional code for your application. Another option doesn’t require touching your application code; it only requires additional configuration, and that’s using a service worker.

What’s a service worker?

A service worker is a small piece of Javascript code that runs in the browser independently from your application. A service worker can be an HTTP proxy between your front-end code and server. It can intercept all HTTP traffic between your Angular application and any remote server.

How to enable service workers in Angular?

Run the command: ng add @angular/pwa

That’s it! You can read more about what the command does in the official documentation. The idea is that instead of writing our service worker code, we let the Angular API take care of that and generate the service worker based on our config.

How to configure what to cache, and for how long?

Angular generates a file called ngsw-config.json. In that file, you can specify which URLs you want to cache, for how long, and if you wish to optimize for freshness (use the cache only if the application is offline) or performance (use the cache as much as possible even if the app is online).

For instance, data that doesn’t change very often (a list of countries or currencies) could be cached for weeks or months, while dynamic data (a list of Tweets or user preferences) could be cached for just a few minutes:

You can find a complete example of such ngsw-config.json here. The full documentation for all supported options can be found here.

Service workers are part of Progressive Web Apps (PWAs). If you want to learn more about that, here’s a quick PWA tutorial of mine.

Customized Deferred Loading with “when”

Last month, I introduced the defer block and its trigger options to perform lazy-loading of a template block with various options.

One of the most flexible ways to user defer is to use the when condition because it allows us to load some code based on a boolean value – which means we have complete control over when to switch that value to true.

Maybe we want to do it once we receive a response from the server or wait for the user to click on a button, or both, for instance:

Another interesting feature is that when can be combined with other triggers. In that case, the first condition to be met would lazy-load the block of code, acting similarly to a logical OR:

And, of course, we can still use a placeholder to display before the block is loaded, as illustrated above.

Make types from JSON samples

First, a quick announcement: I’m running a donation-based online Angular Signals Workshop on December 14th and January 18th. If you’re interested, feel free to show your interest here, and remember that you don’t have to pay anything if you don’t want to or can’t.

Earlier this year, I shared how to generate type definitions for Typescript using json2ts, but that website has disappeared. A suggested superior alternative is Quicktype, which can also create DTOs and has several config options.

Recently, I heard about another option called MakeTypes. It’s as simple as the two previous tools, and it can also be downloaded via npm to be part of your local development process if that’s what you want:

Again, all you need to do is copy-paste your sample JSON and get instant Typescript interfaces (or proxy classes) to use in your project. And if you don’t want to use a website to create your types, head to the NPM page to download the tool.

ng-conf 2024 early bird pricing ends soon

I’ve already mentioned that ng-conf is the only conference I wouldn’t miss for any reason, and ng-conf 2024 will be no exception to that rule. I want to bring your attention to the fact that the conference is scheduled early next year: March 20-21, 2024 (it was in June 2023).

Early bird pricing ends on December 1st, and prices will go up by $100, so if you plan on attending, now is the time to score the best-priced tickets. If you can’t attend in person, there is an option to attend remotely as well, and the price seems to be the same, but it includes an additional pre-conference workshop.

In any case, I’ll be there (on stage or not, I don’t know yet), so if you come over to Salt Lake City, feel free to say hi.

routerLinkActive directive

Have you ever wondered how to highlight a specific HTML element, such as a link or a button, when a particular URL is selected? Something similar to this:

The good news is that there is a specific directive for this called routerLinkActive. Here is how you can use it:

The value set to routerLinkActive is the name of a CSS class (or several CSS classes) that gets applied to the HTML element when the current URL path matches the path of the routerLink directive on that same element. In other words, if the path is page1, then the button element has an active class applied to it.

As a result, all I did to style the above example was add that CSS class definition to my global CSS file:

And that’s it! Note that the directive supports several other options documented here:

You can see my example in action on Stackblitz here.

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.

Code Challenge #1: shareReplay

One of the cool things about teaching Angular, running an Angular certification program, and interacting with hundreds of developers (and code bases) all around the world is that I get to see a lot of good ideas but also a lot of repeated mistakes.

Today, I want to share a small code challenge inspired by repeatedly seen examples over the past few weeks, so you can learn from these examples and won’t make these mistakes in the future.

Here is an example of service for you to look at:

The challenge I have for you is to answer these questions:

  1. What do you think is the requirement behind the code in that service? Why use the shareReplay operator?
  2. Assuming that three different components call the getData() method in their constructor to get an Observable and subscribe to it using the async pipe, how many requests will be made to the API server?
  3. Is the original requirement met or not? How to fix that code if it isn’t working correctly?

I’ll give you these answers tomorrow. In the meantime, feel free to reply with your own answers if you want.

Short video recaps of Angular 17 features

In case you missed it, the Angular team has created a playlist of all Angular 17 features in (mostly) short videos with highlights and examples. Those are, of course, similar to the content covered in the newsletter last week, but here are some direct links to the shortest and most interesting videos:

Remember that it’s essential to use a recent version of Angular and that upgrading often is a lot easier than delaying upgrades repeatedly.