Monday, November 27, 2023

Angular17 - Deferred Loading Using Defer Block

Angular17 - Deferred Loading Using Defer Block

Angular 17 recently came out with several exciting updates.it has an exciting new feature called deferred loading

Lazy loading is a method that helps web apps load things like scripts only when necessary. Instead of loading everything at the start, it waits to load less important stuff until the user does something like interacting with the page or scrolling to a certain point.

Lazy loading improves the user experience by making the initial page load faster. This means users can begin using the app sooner while the less important parts load quietly in the background. It also decreases the amount of internet data needed and eases the strain on the server.

In earlier versions of Angular, we were able to load a specific part of the application later using the Router, or by using dynamic imports along with ngComponentOutlet.

Angular17 now has a @defer control block enabling lazy-loading of the content of the block. Lazy-loading also applies to the dependencies of the content of the block: all the components, directives and pipes will be lazy-loaded, too.

I will demonstrate the key aspects of lazy loading in Angular 17, such as

  • Using @defer with a logical expression
  • Using @defer with a declarative trigger condition

Using @defer with a logical expression

In the below example, I make a checkbox and bind it to the isChecked property. Initial value of isChecked is false, so at the start, the checkbox is unccheked, and the content inside the @defer block doesn't appear.

<h2>@defer with a logical expression</h2>

<div>
  <input #checkboxDefer type="checkbox" [checked]="isChecked" (change)="onChange()" id="checkboxDefer" />
  <label for="checkboxDefer">Check this checkbox to load the component</label>
</div>
<br>

@defer (when isChecked) {
<app-defer1 />
}
@placeholder {
<span>Placeholder</span>
}
@error {
<span>Error</span>
}
@loading(minimum 1s) {
<span>Loading...</span>
}

The @defer (when logical_expression) creates @defer block with the logical expression. I use the isChecked property as a logical expression, as it evaluates to a boolean value.

In the above example, we have four block types under the @defer block. These are-

  • An @defer block in Angular displays its content only when the isChecked turns true. Inside, there's a child component: <app-defer1 />.
  • A @placeholder block, it's rendered initially, before the @defer block is triggered
  • When the @defer block activates, Angular fetches its content from the server. While it loads, the @loading block is displayed.
  • If the loading fails, Angular shows the @error block

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

Let's explore this code! When we launch the app, the isChecked is false. This means the @defer block doesn't triggered, and the content of the @placeholder block is visible.

place holder block content

When we check the checkbox, the isChecked turns true. Angular then loads the @defer block's content. It replaces the content of the @placeholder block and shows the @loading block. I set a minimum duration for this block to appear for at least one second. There's an option to set an "after" condition, which sets the minimum time to wait before the @loading block appears. If the content from the @defer block loads within this time, Angular won't display the @loading block.

Content of the @loading block is visible for one second:

loading block content

Then the content of the @defer block, the <app-defer1> component is shown:

defer block content

In the Developer tools, it's visible that after checking the box, Angular loaded a chunk of the application, which includes the content from the @defer block.

loading chunk

Using @defer with a declarative trigger condition

Deferred blocks can be triggered using various declarative types:

  • on interaction
  • on hover
  • on idle
  • on timer
  • on viewport

Below are the examples of all these:

  • @defer on interaction:Angular renders the on interaction block, when the user interacts with its @placeholder block. An interaction can be a click, touch focus, or input events:
    <h3>@defer on interaction</h3>
    @defer (on interaction) {
    <span>Clicked</span>
    }
    @placeholder {
    <span>Placeholder (click on it!)</span>
    }
    
  • @defer on idle:Angular renders the on idle block, when the browser reaches an idle state after the page has been loaded:
    <h3>@defer on idle</h3>
    @defer (on idle) {
    <span>Browser has reached an idle state</span>
    }
    @placeholder {
    <span>Placeholder</span>
    }
    
  • @defer on hover:Angular renders the on hover block, when the user hovers over its @placeholder block:
    <h3>@defer on hover</h3>
    @defer (on hover) {
    <span>Hovered</span>
    }
    @placeholder {
    <span>Placeholder (hover it!)</span>
    }
    
  • @defer on timer:The on timer block is rendered after the specified time is elapsed:
    <h3>@defer on timer(5s)</h3>
    @defer (on timer(5s)) {
    <span>Visible after 5s</span>
    }
    @placeholder {
    <span>Placeholder</span>
    }
    
  • @defer on viewport:Angular renders the on viewport block, when the placeholder enters the browser's viewport:
    <h3>@defer on viewport</h3>
    @defer (on viewport) {
    <app-defer2 text="The block entered the viewport" />
    }
    @placeholder {
    <span>Placeholder</span>
    }
    
  • Prefetch:Next to a trigger condition, we can specify an additional prefetch condition.In prefetch, Angular loads the content of the @defer block, but it's not rendered, the @placeholder remains visible.Then we hover on the placeholder, and Angular renders the prefetched block.
    <h3>Prefetch</h3>
    @defer (on interaction; prefetch on hover) {
    <app-defer3 />
    }
    @placeholder {
    <span>Placeholder (hover it, then click on it!)</span>
    }
    

The full source code is available here:

Happy coding!! 😊

No comments:

Post a Comment

^ Scroll to Top