Angular 17: A Hands-On Journey into Deferred Loading

A journey of discovering the new features of Angular 17

Saif eddine hasnaoui
6 min readNov 2, 2023
Photo by Borderpolar Photographer shared on Unsplash

Introduction

Being at the forefront of web development trends has always been a passion of mine. When I caught wind of the upcoming release of Angular 17 (last up-to-date version is 17.0.0-rc.1) and the thrilling enhancements it promised, I felt an irresistible urge to delve deeper. So, just like any sensible developer (and slightly curious explorer), I decided to create a little side project to see what all the fuss was about.

Throughout this article and more to come, I’ll take you through my journey of exploring Angular 17 and show you the important changes and new features that developers can benefit from. So, get ready to dive into the latest Angular version with me and stay tuned for the ongoing exploration in the upcoming articles.

You can access all the source code examples featured in this article here https://github.com/hasnaoui-saif/Angular17/tree/main/src/app/deferred-loading

Deferred loading

First, let us wrap our head about the concept of the Lazy loading first. It is a trick that helps web apps load things, like scripts, only when you need them. So, instead of cramming everything in at the start, lazy loading makes the app wait until you do something, like scrolling or clicking, before fetching non-essential stuff. This not only makes your app faster, since it doesn’t have to carry around all the unnecessary baggage from the start , but also saves your precious data and gives the server a breather.

In the older versions of Angular, we had some cool ways to do lazy loading, like using the Router or dynamic imports. But guess what? In Angular 17, the Angular wizards have taken it to the next level with a new thing called @defer Deferred Loading — RFC

Logical expressions

In the initial example, I created a button and bind it to the isClicked signal. The signal's default value is false, so initially the isClicked is false, and the content of the @defer block is not rendered.

<button (click)="isClicked.set(true)" >
Click on me to load <strong>app-child</strong> component
</button>

@defer (when isClicked()) {
<app-child/>
}

@placeholder {
<span class='placeholder'>Placeholder</span>
}

@error {
<span class='error'>Error</span>
}

@loading(minimum 1s) {
<span class='loading'>Loading...</span>
}

Let us break this down:

The @defer (when logical_expression) {} code creates a special block with a condition. In our case, we’re using the isClicked() signal as the condition.

Inside this @defer block, there are three optional blocks:

  1. @placeholder block: Initially shown before the @defer condition is met.
  2. When the @defer condition is met, Angular loads content e.g. from the server, and you see the @loading block.
  3. If loading fails, the @error block is displayed.

The use of the @placeholder, @loading and @error blocks are optional, so that means we can use standalone @defer blocks too.

Let’s see how this code works! When we open the app, the isClicked() signal is false, so the @defer block is not triggered and the content of the @placeholder block is visible:

Initially, the condition is false and we only see the @placeholder

Now, when we click on the button, the signal isClicked() turns true. As a result, Angular loads the content inside the @defer block, replacing the content of the @placeholder block with the content of the @loading block. I’ve set a minimum duration condition for this block, ensuring it’s visible for at least one second. If the content inside the @defer block loads within this waiting period, Angular won’t show the “@loading” block.

@loading block is shown just after clicking the button

Afterward, the content inside the @defer block, which includes the <app-child> component, is visible.

child component is now visible

The interesting part is that we can observe the child component loading shortly after clicking the button. One might wonder how this happens ?

To find out, let’s open the Developer tools. There, we can see that immediately after the button click, Angular loads a new chunk of the application, which includes the content of the @defer block.

Chunk loading

Now, for a bit of tech drama, we reload the app, clear the Network tab, and then deliberately blocking network requests in the browser. Upon clicking the button, Angular starts loading the content of the @defer and displaying the @loading block. But, we know that the loading will fail due to the network connection, so Angular shows the content of the @error block.

@error block is displayed in case of error

Declarative triggers

As logical expressions, @defer supports the following declarative trigger types:

  • On interaction

Angular renders the on interaction block when the user interacts with the @placeholder block. This interaction can include actions like clicking, touching, focusing, or input events.

@defer (on interaction) {
<span>Clicked</span>
}
@placeholder {
<span>Click me!</span>
}
  • on hover

Angular displays the on hover block when the user hovers over its @placeholder block.

@defer (on hover) {
<span>Hovered</span>
}
@placeholder {
<span>Hover me!</span>
}
  • on idle

Angular displays the on idle block when the browser reaches an idle state after the page has finished loading.

@defer (on idle) {
<span>Browser has reached an idle state</span>
}
  • on timer

The on timer block is displayed once the specified time has passed.

@defer (on timer(5s)) {
<span>I am visible after 5s</span>
}
@placeholder {
<span>Placeholder</span>
}
  • on viewport

Angular displays the on viewport block when the placeholder enters the browser’s viewport.

@defer (on viewport) {
<span>I am only visible when my placeholder is within the viewport</span>}
@placeholder {
<span>Placeholder</span>
}

Resource Prefetching

Another valuable feature for deferred loading is the capability to pre-fetch dependencies in advance of a user’s interaction. This is particularly advantageous for minimizing delays when a deferred block becomes active. The prefetch syntax operates in conjunction with the primary defer condition and employs triggers (when and/or on), similar to defer.

@defer (on interaction; prefetch on hover) {
...
}

Migration ❤️

One of the remarkable aspects of Angular is their commitment to facilitating the migration processes, and this time is no different. The Angular team is actively developing a schematic to assist us in transitioning our existing code to the new syntax. This schematic is expected to be accessible once the new version is officially released.

Additionally, according to the RFCs and feedback from the Angular team, structural directives will remain a fundamental part of Angular, ensuring that we can continue using them just as we do today.

Conclusion

In this article, I introduced you to the cool new stuff in Angular 17. We talked about how those deferred blocks do their thing and how you can play them around with conditions. I hope you found my tutorial helpful and not as confusing as trying to assemble IKEA’s furniture with vague instructions!

Coming up next, we’ll dive into the sequel of this article series and explore the other new control flow features like @if, @else, @switch, and @case blocks in Angular 17.

--

--

Saif eddine hasnaoui
Saif eddine hasnaoui

Written by Saif eddine hasnaoui

Experienced, motivated, and autonomous Full Stack Engineer who worked on diverse applications, ensuring code quality, scalability, and business requirements.

No responses yet