I also found the animations doc on angular.io to be incomplete. I used the example code and made a couple minor changes to make it work with the code from their TOH app tutorial.
TL;DR
Add a state="inactive" property to the hero.ts hero class to track each hero's animation state.
In HTML, change their (click)="hero.toggleState()" method binding to (click)="toggleState(hero)" and write that method in the HeroesComponent class:
toggleState(hero: Hero) {
hero.state = (hero.state === 'active' ? 'inactive' : 'active');
}
Rewire onSelect() method so that gotoDetail() navigation works.
Working plunk that follows steps below
Here is the plunker they provide with everything complete through section 5 - routing. Use it to follow along, if you'd like.
I'm going to walk through how to modify that plunk to achieve the first animation in their animations doc.
The first code they partially walk you through in the animations docs is to add animated active/inactive states to selected heroes in the Heroes view (as opposed to the dashboard view):
import { Component, Input, trigger, state, animate } from '@angular/core';
import { Heroes } from './hero.service';
@Component({
moduleId: module.id,
selector: 'hero-list-basic',
template: `
<ul>
<li *ngFor="let hero of heroes"
[@heroState]="hero.state"
(click)="hero.toggleState()">
{{hero.name}}
</li>
</ul>
`,
styleUrls: ['hero-list.component.css'],
animations: [
trigger('heroState', [
state('inactive', style({
backgroundColor: '#eee',
transform: 'scale(1)'
})),
state('active', style({
backgroundColor: '#cfd8dc',
transform: 'scale(1.1)'
})),
transition('inactive => active', animate('100ms ease-in')),
transition('active => inactive', animate('100ms ease-out'))
])
]
})
export class HeroListBasicComponent {
@Input() heroes: Heroes;
}
Above, their (animations example) code parallels the code in app/heroes.component.ts (from the plnkr) and note that the html/css have been extracted into separate files on plnkr. I presume most who read this have followed the tutorial and are familiar with this code.
heroes.component.html
The new animations will basically replicate the existing bindings on each hero <li>, so delete these two lines -- because they would conflict if we kept them -- we're going to bring that functionality back with animation states.
<ul class="heroes">
<li *ngFor="let hero of heroes">
--------->[class.selected]="hero === selectedHero"
--------->(click)="onSelect(hero)">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
</ul>
new html from animations example:
<ul class="heroes">
<li *ngFor="let hero of heroes"
[@heroState]="hero.state"
(click)="hero.toggleState()">
<span class="badge">{{hero.id}}</span> {{hero.name}}
</li>
</ul>
I didn't want to add the toggleState method to the hero class, I wanted it in the component that calls it. So I changed the click binding to
(click)="toggleState(hero)"
and simply pass the clicked hero to the method we still need to write.
A hero doesn't have the property state yet so let's add that in app/hero.ts:
add state:string = "inactive"; to the list of properties.
Now let's get back to heroes.component.ts, import our animations dependencies, add the animations metadata in @Component, and create the toggleState() method. We want to keep the onSelect() method we removed from html, we'll alter it and reuse it in a moment.
Up top, replace
import { Component, OnInit } from '@angular/core';
with
import { Component, OnInit, trigger, state, style, transition, animate } from '@angular/core';
Append the animations metadata after styleUrls: [ ... ],:
animations: [
trigger('heroState', [
state('inactive', style({
backgroundColor: '#eee',
transform: 'scale(1)'
})),
state('active', style({
backgroundColor: '#cfd8dc',
transform: 'scale(1.1)'
})),
transition('inactive => active', animate('100ms ease-in')),
transition('active => inactive', animate('100ms ease-out'))
])
]
In the HeroesComponent class add the following method:
toggleState(hero: Hero) {
hero.state = (hero.state === 'active' ? 'inactive' : 'active');
}
So that all works. Now let's unbreak the hero detail. The hero detail was a little blurb after the list that shows which hero is selected accompanied by a button that navigates to the detail/:id route. But now it's gone. The onSelect() method we detached was launching that.
Let's rename onSelect() to updateSelectedHero() and then call it from inside toggleState():
updateSelectedHero(hero: Hero): void {
this.selectedHero = hero;
}
toggleState(hero: Hero) {
hero.state = (hero.state === 'active' ? 'inactive' : 'active');
this.updateSelectedHero(hero);
}
aaand we're back in business. The hero detail shows up and it's View Details button calls gotoDetail(). There are obnoxious UI flaws that need ironed out, but you get the idea.
My finished plunk