Angular is a popular front-end framework made by Google. Like other popular front-end frameworks, it uses a component-based architecture to structure apps.
In this article, we look at how to apply transitions and triggers when *ngIf
is being run.
Predefined States and Wildcard Matching
We can use an asterisk to match any animation state. This is useful for defining transitions that apply regardless of the HTML element’s start or end state.
For example, we can use the asterisk as follows:
app.component.ts
:
import { Component } from "@angular/core";
import {
state,
style,
transition,
animate,
trigger
} from "@angular/animations";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"],
animations: [
trigger("openClose", [
state(
"open",
style({
height: "250px",
opacity: 1,
backgroundColor: "pink"
})
),
state(
"closed",
style({
height: "100px",
opacity: 0.5,
backgroundColor: "green"
})
),
transition("* => closed", [animate("1s")]),
transition("* => open", [animate("0.5s")])
])
]
})
export class AppComponent {
isOpen = true;toggle() {
this.isOpen = !this.isOpen;
}
}
app.component.html
:
<button (click)="toggle()">Toggle</button>
<div [@openClose]="isOpen ? 'open' : 'closed'">
{{ isOpen ? 'Open' : 'Closed' }}
</div>
In the code above, we have:
transition("* => closed", [animate("1s")]),
transition("* => open", [animate("0.5s")])
The code above indicates that we animate for a second when we transition from any state to the closed
state.
When we transition from anything to the open
state, we animate for half a second.
Using Wildcard State with Multiple Transition States
We can have more than 2 states in our transition. To use the asterisk to transition between multiple states as follows:
app.component.ts
:
import { Component } from "@angular/core";
import {
state,
style,
transition,
animate,
trigger
} from "@angular/animations";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"],
animations: [
trigger("openClose", [
state(
"open",
style({
height: "250px",
opacity: 1,
backgroundColor: "pink"
})
),
state(
"inProgress",
style({
height: "130px",
opacity: 0.75,
backgroundColor: "orange"
})
),
state(
"closed",
style({
height: "100px",
opacity: 0.5,
backgroundColor: "green"
})
),
transition("* => closed", [animate("1s")]),
transition("* => open", [animate("0.5s")]),
transition("* => inProgress", [animate("2.5s")]),
transition("inProgress => closed", [animate("1.5s")]),
transition("* => open", [animate("0.5s")])
])
]
})
export class AppComponent {
states = \["open", "closed", "inProgress"\];
index = 0;
state = "open"; changeState() {
this.index = (this.index + 1) % this.states.length;
this.state = this.states\[this.index\];
}
}
app.component.html
:
<button (click)="changeState()">Toggle</button>
<div [@openClose]="state">
{{ state }}
</div>
In the code above, we have multiple transition states and we used the wildcard to specify the animation length.
We cycled through the states with the changeState
method.
We can use the void
state to configure transitions for an element that’s entering or leaving a page.
It can be combined with the wildcard. It works as follows:
* => void
— applies when the element leaves a view regardless of what state it was before it leftvoid => *
— applies when the element enters a view regardless of what state it assumes when entering- The
*
state matches any state includingvoid
.
Animating Entering and Leaving a View
We can animate entering a leaving a view by styling the in
state.
Then we animate the transition between the void
and wildcard and vice versa to run animation when the element is being added removed and added respectively.
We can do that as follows:
app.component.ts
:
import { Component } from "@angular/core";
import {
state,
style,
transition,
animate,
trigger
} from "@angular/animations";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"],
animations: [
trigger("flyInOut", [
state("in", style({ transform: "translateX(0)" })),
transition("void => *", [
style({ transform: "translateX(-100%)" }),
animate(100)
]),
transition("* => void", [
animate(100, style({ transform: "translateX(100%)" }))
])
])
]
})
export class AppComponent {}
app.component.html
:
<button (click)="show = !show">Toggle</button>
<div @flyInOut *ngIf="show">
foo
</div>
In the code above, we have the flyInOut
trigger which has the transition from void
to *
, which is applied when the div with the *ngIf
is inserted.
The in
state has the style for the div when it’s displayed.
Then the other transition is applied when the div is being removed.
In the template, we have div with the *ngIf
with the word ‘foo’ inside and a Toggle button that toggles the div on and off.
Then when we click the Toggle button, we see the word ‘foo’ fly to the right before disappearing since we have:
transition("* => void", [
animate(100, style({ transform: "translateX(100%)" }))
])
as the div is being removed with *ngIf
.
:enter and :leave Aliases
:enter
is short for void => *
and :leave
is shorthand for * => void
.
So we can write:
transition ( ':enter', [ ... ] ); // alias for void => *
transition ( ':leave', [ ... ] ); // alias for * => void
Conclusion
We can animate *ngIf
transitions by adding the * => void
and void => *
transitions.
*
stands for any state and void
is the state when an element leaves the screen.
:enter
and :leave
are short for void => *
and * => void
respectively.