DEV Community

Cover image for Display Angular @empty block at the right time!
Gérôme Grignon
Gérôme Grignon

Posted on • Originally published at gerome.dev

Display Angular @empty block at the right time!

The new Control Flow syntax for Angular has been introduced with Angular 17 release, as a developer preview.

It replaces *ngIf, *ngFor, and *ngSwitch with a new syntax that is more expressive and easier to read.

@for(article of articles$ | async; track article.id) {
  <article>
    <h2>{{ article.title }}</h2>
    <p>{{ article.content }}</p>
  </article>
}
Enter fullscreen mode Exit fullscreen mode

The Angular team added a new feature to enhance the @for block: the @empty block.

The content of this block will be displayed if the list is empty or undefined.

@for(article of articles$ | async; track article.id) {
  <article>
    <h2>{{ article.title }}</h2>
    <p>{{ article.content }}</p>
  </article>
} @empty {
  <p>No articles found</p>
}
Enter fullscreen mode Exit fullscreen mode

The problem

A common misconception is to think that the @empty block is evaluated only once the data is retrieved from an asynchronous call.

In most usecases, you iterate over a list of items retrieved from an API.

As the API call is asynchronous, the list is undefined/empty at the component initialization.

From our point of view:

  1. The list is evaluated as empty
  2. The data is retrieved from the API
  3. The list is evaluated once again and display the empty block if the list is empty

From an end user point of view:

  1. The empty block is displayed at the beginning
  2. The view is updated with the list of items once the data is retrieved if a non-empty list is returned

It means we are displaying the empty block at the wrong time!

For a second (or more depending on your API response time), the user sees the empty block before the list is displayed.
They might think that the list is really empty, while it's not.

The solution

You need to wrap your existing logic to deal with the loading state of the list.

@if(articles$ | async as articles) {
    @for(article of articles; track article.id) {
    <article>
        <h2>{{ article.title }}</h2>
        <p>{{ article.content }}</p>
  </article>
    } @empty {
        <p>No articles found</p>
    }   
} @else {
    <p>Loading...</p>
}
Enter fullscreen mode Exit fullscreen mode

There, instead of displaying the @empty block while you are waiting for the list to be retrieved, you display a loading message.
The @empty block will be evaluated once the list is retrieved and displayed at the right time.

Top comments (0)