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.

Vote for the future of this newsletter in 2024

There’s only a month and a half left in 2023, and my goal is to keep publishing daily updates till the end of the year, except on public US holidays (such as Thanksgiving and Black Friday later this week).

In 2024, I’m thinking about slowing the cadence down to weekly or even monthly emails, and I would love to hear your input on that. As you can imagine, publishing content every day is quite a big task, and I’ve done it even when on vacation so far this year. I would prepare all posts before traveling – which means a lot more work upfront.

The only way I could keep doing daily posts was if there was some sort of paid subscription model, but I’m not sure if that option would be popular.

As a result, I’d appreciate your feedback and input on what you’d like to see in 2024 and if a daily newsletter with a paid subscription is something you’d be OK with or not at all. A weekly or monthly option would remain free, of course.

Feel free to hit reply and let me know.

Angular 17: Signals, Server-side rendering, and Standalone

We’re not done with Angular 17 updates! Here are a few more updates on Signals, Standalone, and Server-side rendering.

Signals

Signals have graduated from developer preview and are now officially part of the framework, except the effect function that is still being tweaked by the Angular team. A big step for Angular Signals.

Standalone

With Angular 17, a new Angular app is generated with standalone components by default. You can upgrade your Angular CLI to test that out, and if you don’t want to use standalone by default and your new apps, this feature can be turned off in angular.json with the following config:

   "projects": {
    "my-app": {
      "schematics": {
        "@schematics/angular:component": {
          "standalone": false
        }
     Code language: JavaScript (javascript)

Server-side rendering

With Angular 17, you can create an app that uses server-side rendering with a single command:

ng new --ssr

If you want to add server-side rendering to an existing app, you can run:

ng add @angular/ssr

It’s also possible to pre-render an Angular app using:

ng build --prerender

That way, you don’t need Node.js hosting and can use static, pre-rendered HTML files. I’ll explore this more in the newsletter before the end of the year.

On that same topic of server-side rendering, hydration graduated developer preview, which means an app rendered on the server side won’t rebuild its entire DOM in the browser. Instead, Angular will take over that DOM and re-hydrate it with up-to-date data as needed.

Angular 17: Simplifying style(s)

A major focus of the Angular team over the past two years has been to improve the developer experience by removing some of the common annoyances in the framework (better error messages, for instance). This is often referred to as “quality of life” improvements, and the Angular 17 feature I want to cover today is undoubtedly one of those.

Have you ever wondered why the component decorator always had a styleUrls or styles attribute even when 99.9999% of the time, we need one style URL or CSS style?

Well, I have good news for you! Angular 17 introduced a styleUrl attribute (singular) for a single style file:

And the other styles attribute has more flexibility as well as it now supports a single string or an array of strings, which means all options are available now:

A simple change that makes our life easier!

How to update your Angular CLI?

We touched on many Angular 17 updates so far, and if you want to test those out on a fresh new project, you’ll need to upgrade your Angular CLI to v17.

Here is the most straightforward command to upgrade your global Angular CLI to the latest version:

npm install -g @angular/cli@latest

That’s it! The -g flag indicates we want to install that CLI globally, and the @latest at the end ensures we’re getting the latest stable version.

Angular 17: New devtools injector tree view

Another Angular 17 update is the release of a new DevTools panel called Injector Tree. It’s a good option to visualize both your element hierarchy and injector hierarchy, and it is accessible as a third tab in the Angular DevTools browser extension available for Chrome, Firefox, and Edge:

When we click on that tab, a tree view of all hierarchies shows up on the screen:

For a clearer view, we can check the option “hide framework injectors” to focus on our code:

Clicking on an injector (such as root) shows the list of all injectables/services available in that injector:

This new tab seems to be just getting started, and more information will be added later. Even though the Devtools is a browser extension, the Injector tree tab only works for apps using Angular v17+. I tried an Angular v16 app with no success.

Angular 17: New esbuild builder with Vite

Who doesn’t like faster builds? Since Angular 2, the Angular team has consistently worked on making our builds quicker and faster. Angular 16 included a developer preview of a new build system based on esbuild and Vite.

With Angular 17, this feature is now enabled by default for new apps, with reported speed improvements of over 67% in most applications.

To enable this new build system in existing apps (that use v16+), open your angular.json file and look for all the places where @angular-devkit/build-angular:browser is used:

Then, replace those instances with @angular-devkit/build-angular:browser-esbuild

And your next run of ng serve or ng build will automatically use this new build system. Nice and easy! If you use server-side rendering or have tweaked the builders in the past, you’ll want to look at the extra instructions listed on this page.

Angular 17: Trigger options for @defer

Yesterday, we introduced the new @defer bloc to lazy-load components on the screen. We saw that @defer includes several config options to display errors, placeholder, and loading templates.

Today, let’s focus on the possible triggers for such lazy loading.

idle

This is the default option. Will load the contents of that block once the browser is in an idle state:

viewport

Triggers the deferred block when its content enters the viewport. For instance, that would be when the user scrolls down, and the block becomes “visible.” Note that this option requires a placeholder (used to detect when the element comes into the viewport):

Another interesting option is to load the deferred block when another specified element makes it into the viewport using a template reference variable. That option does not require a placeholder:

interaction

Waits for the user to interact with the placeholder to load the deferred block. Even better, this trigger can be combined with another element so you can lazy-load a component on a button click, for instance:

The above code can be tested on Stackblitz here.

hover

Similar to the two previous examples. Waits for the user to hover over the placeholder or a specified element:

immediate and timer

immediate triggers the deferred block immediately as soon as Angular has finished rendering. Timer waits for a specified delay:

You can see most of these different examples on Stackblitz here. There are a few more options for @defer that I’ll cover later to keep this newsletter short and readable. It’s incredible what such a small API can do!