I'm having an issue with fading in and out an error message while also using *ngIf. The fade-in works fine, but the fade out does not work. Instead, the text just disappears (as if set to display:none), even though the *ngIf does not take effect until the fade out is complete. I have tried converting to use string enumerations and numeric values but get the same effect. Is there an issue with my animations configuration?
Linked stackblitz is using Angular 10, I'm on Angular 11.0.7 (latest).
https://stackblitz.com/edit/angular-ivy-bsuupd?file=src/app/form-error.component.ts
@Component({
selector: "app-form-error",
animations: [
trigger("fadeInOut", [
state("false", style({ opacity: 0 })),
state("true", style({ opacity: 1 })),
transition("true <=> false", animate(500))
])
],
template: `
<p>showError is {{ showError }}</p>
<p>fadeError is {{ fadeError }}</p>
<ng-container *ngIf="showError">
<h1 [@fadeInOut]="{ value: fadeError }">{{ errorText }}</h1>
</ng-container>
`
})
export class FormErrorComponent implements OnInit, OnChanges {
@Input() errorText: string;
showError: boolean = false;
fadeError: boolean = false;
constructor() {}
ngOnInit(): void {}
ngOnChanges(changes: SimpleChanges): void {
if (this.errorText) {
this.showError = true;
setTimeout(() => {
// lets fade in begin after ngIf takes effect (works fine)
this.fadeError = true;
});
} else {
this.fadeError = false; // this should start fade, but just hides the text immediately
setTimeout(() => {
// delays the ngIf until fade out is done
this.showError = false;
}, 500);
}
}
}
The problem is that you are removing the text altogether by doing:
this.errorMessage = null;
The actual animation is working fine, the issue is that you are removing the text to be displayed, so you don't even see the animation as the text changes immediately (into nothing).
You can see what I mean by looking at this:
https://stackblitz.com/edit/angular-ivy-t3ft5x?file=src%2Fapp%2Fhello.component.ts
I am simply treating 'test'
as you're treating null
As a solution you can use a setter for the text and a boolean flag as:
errorTextToShow: string;
showErrorText: boolean;
@Input() set errorText(value: string) {
if(!!value){
this.errorTextToShow = value;
}
this.showErrorText = !!value;
}
and in your template have:
<h1 [@fadeInOut]="{ value: fadeError }">{{ errorTextToShow }}</h1>
In this way to achieve what you wanted and don't delete the text when setting the input to null so that the fade-out effect can still be present.
You can check out the solution here:
https://stackblitz.com/edit/angular-ivy-fwpgcw?file=src%2Fapp%2Fform-error.component.ts