Let’s say I have the following blocks :
@defer (onSignal()) {
if (succesOnRetrievingAsyncData()) {
<succes-component />
} else {
<error-component />
<button click="retryAsyncCall()"> Retry </button>
}
} @placeholder(minimum 1s) {
<img src="placeholder.png" />
}
As it is mentioned in the following doc : https://angular.dev/guide/defer#triggers
If the when condition switches back to false, the defer block is not reverted back to the placeholder. The swap is a one-time operation. If the content within the block should be conditionally rendered, an if condition can be used within the block itself
I would like to perform again the async call when user clicks on the button, and trigger the @defer/@placeholder blocks to show the placeholder image.
How can I achieve that ?
To my knowledge defer
only runs once, you have to wrap another if condition to handle all subsequent cases!
@defer (on idle; when onSignal()) {
@if (onSignal()) {
@if (succesOnRetrievingAsyncData()) {
<div>success</div>
} @else {
<div>error</div>
<button (click)="retryAsyncCall()"> Retry </button>
}
} @else {
<img src="placeholder.png" />
}
} @placeholder(minimum 1s) {
<img src="placeholder.png" />
}
Full Code:
import { Component, signal } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
@Component({
selector: 'app-root',
standalone: true,
template: `
@defer (on idle; when onSignal()) {
@if (onSignal()) {
@if (succesOnRetrievingAsyncData()) {
<div>success</div>
} @else {
<div>error</div>
<button (click)="retryAsyncCall()"> Retry </button>
}
} @else {
<img src="placeholder.png" />
}
} @placeholder(minimum 1s) {
<img src="placeholder.png" />
}
`,
})
export class App {
name = 'Angular';
retry = false;
onSignal = signal(false);
ngOnInit() {
setTimeout(() => {
this.onSignal.set(true);
}, 3000);
}
retryAsyncCall() {
this.onSignal.set(false);
setTimeout(() => {
this.onSignal.set(true);
}, 5000);
}
succesOnRetrievingAsyncData() {
return this.retry;
}
}
bootstrapApplication(App);
Stackblitz Demo