docs: Refresh content on routable animations for router guide (#20023)
PR Close #20023
This commit is contained in:
parent
c8817f39a9
commit
c9fece997c
@ -13,33 +13,34 @@ describe('Router', () => {
|
|||||||
|
|
||||||
function getPageStruct() {
|
function getPageStruct() {
|
||||||
const hrefEles = element.all(by.css('app-root > nav a'));
|
const hrefEles = element.all(by.css('app-root > nav a'));
|
||||||
const crisisDetail = element.all(by.css('app-root > ng-component > ng-component > ng-component > div')).first();
|
const crisisDetail = element.all(by.css('app-root > div > ng-component > ng-component > ng-component > div')).first();
|
||||||
const heroDetail = element(by.css('app-root > ng-component > div'));
|
const heroDetail = element(by.css('app-root > div > ng-component'));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hrefs: hrefEles,
|
hrefs: hrefEles,
|
||||||
activeHref: element(by.css('app-root > nav a.active')),
|
activeHref: element(by.css('app-root > nav a.active')),
|
||||||
|
|
||||||
crisisHref: hrefEles.get(0),
|
crisisHref: hrefEles.get(0),
|
||||||
crisisList: element.all(by.css('app-root > ng-component > ng-component li')),
|
crisisList: element.all(by.css('app-root > div > ng-component > ng-component li')),
|
||||||
crisisDetail: crisisDetail,
|
crisisDetail: crisisDetail,
|
||||||
crisisDetailTitle: crisisDetail.element(by.xpath('*[1]')),
|
crisisDetailTitle: crisisDetail.element(by.xpath('*[1]')),
|
||||||
|
|
||||||
heroesHref: hrefEles.get(1),
|
heroesHref: hrefEles.get(1),
|
||||||
heroesList: element.all(by.css('app-root > ng-component li')),
|
heroesList: element.all(by.css('app-root > div > ng-component li')),
|
||||||
heroDetail: heroDetail,
|
heroDetail: heroDetail,
|
||||||
heroDetailTitle: heroDetail.element(by.xpath('*[1]')),
|
heroDetailTitle: heroDetail.element(by.xpath('*[2]')),
|
||||||
|
|
||||||
adminHref: hrefEles.get(2),
|
adminHref: hrefEles.get(2),
|
||||||
adminPreloadList: element.all(by.css('app-root > ng-component > ng-component > ul > li')),
|
adminPreloadList: element.all(by.css('app-root > div > ng-component > ng-component > ul > li')),
|
||||||
|
|
||||||
loginHref: hrefEles.get(3),
|
loginHref: hrefEles.get(3),
|
||||||
loginButton: element.all(by.css('app-root > ng-component > p > button')),
|
loginButton: element.all(by.css('app-root > div > ng-component > p > button')),
|
||||||
|
|
||||||
contactHref: hrefEles.get(4),
|
contactHref: hrefEles.get(4),
|
||||||
contactCancelButton: element.all(by.buttonText('Cancel')),
|
contactCancelButton: element.all(by.buttonText('Cancel')),
|
||||||
|
|
||||||
outletComponents: element.all(by.css('app-root > ng-component'))
|
primaryOutlet: element.all(by.css('app-root > div > ng-component')),
|
||||||
|
secondaryOutlet: element.all(by.css('app-root > ng-component'))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,6 +99,7 @@ describe('Router', () => {
|
|||||||
it('saves changed hero details', async () => {
|
it('saves changed hero details', async () => {
|
||||||
const page = getPageStruct();
|
const page = getPageStruct();
|
||||||
await page.heroesHref.click();
|
await page.heroesHref.click();
|
||||||
|
await browser.sleep(600);
|
||||||
const heroEle = page.heroesList.get(4);
|
const heroEle = page.heroesList.get(4);
|
||||||
let text = await heroEle.getText();
|
let text = await heroEle.getText();
|
||||||
expect(text.length).toBeGreaterThan(0, 'hero item text length');
|
expect(text.length).toBeGreaterThan(0, 'hero item text length');
|
||||||
@ -105,6 +107,7 @@ describe('Router', () => {
|
|||||||
const heroText = text.substr(text.indexOf(' ')).trim();
|
const heroText = text.substr(text.indexOf(' ')).trim();
|
||||||
|
|
||||||
await heroEle.click();
|
await heroEle.click();
|
||||||
|
await browser.sleep(600);
|
||||||
expect(page.heroesList.count()).toBe(0, 'hero list count');
|
expect(page.heroesList.count()).toBe(0, 'hero list count');
|
||||||
expect(page.heroDetail.isPresent()).toBe(true, 'hero detail');
|
expect(page.heroDetail.isPresent()).toBe(true, 'hero detail');
|
||||||
expect(page.heroDetailTitle.getText()).toContain(heroText);
|
expect(page.heroDetailTitle.getText()).toContain(heroText);
|
||||||
@ -114,6 +117,7 @@ describe('Router', () => {
|
|||||||
|
|
||||||
let buttonEle = page.heroDetail.element(by.css('button'));
|
let buttonEle = page.heroDetail.element(by.css('button'));
|
||||||
await buttonEle.click();
|
await buttonEle.click();
|
||||||
|
await browser.sleep(600);
|
||||||
expect(heroEle.getText()).toContain(heroText + '-foo');
|
expect(heroEle.getText()).toContain(heroText + '-foo');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -130,7 +134,8 @@ describe('Router', () => {
|
|||||||
const page = getPageStruct();
|
const page = getPageStruct();
|
||||||
await page.heroesHref.click();
|
await page.heroesHref.click();
|
||||||
await page.contactHref.click();
|
await page.contactHref.click();
|
||||||
expect(page.outletComponents.count()).toBe(2, 'route count');
|
expect(page.primaryOutlet.count()).toBe(1, 'primary outlet');
|
||||||
|
expect(page.secondaryOutlet.count()).toBe(1, 'secondary outlet');
|
||||||
});
|
});
|
||||||
|
|
||||||
async function crisisCenterEdit(index: number, save: boolean) {
|
async function crisisCenterEdit(index: number, save: boolean) {
|
||||||
|
@ -1,26 +1,35 @@
|
|||||||
// #docregion
|
// #docregion
|
||||||
import { animate, state, style, transition, trigger } from '@angular/animations';
|
import {
|
||||||
|
trigger, animateChild, group,
|
||||||
|
transition, animate, style, query
|
||||||
|
} from '@angular/animations';
|
||||||
|
|
||||||
// Component transition animations
|
|
||||||
export const slideInDownAnimation =
|
// Routable animations
|
||||||
|
export const slideInAnimation =
|
||||||
trigger('routeAnimation', [
|
trigger('routeAnimation', [
|
||||||
state('*',
|
transition('heroes <=> hero', [
|
||||||
style({
|
style({ position: 'relative' }),
|
||||||
opacity: 1,
|
query(':enter, :leave', [
|
||||||
transform: 'translateX(0)'
|
style({
|
||||||
})
|
position: 'absolute',
|
||||||
),
|
top: 0,
|
||||||
transition(':enter', [
|
left: 0,
|
||||||
style({
|
width: '100%'
|
||||||
opacity: 0,
|
})
|
||||||
transform: 'translateX(-100%)'
|
]),
|
||||||
}),
|
query(':enter', [
|
||||||
animate('0.2s ease-in')
|
style({ left: '-100%'})
|
||||||
]),
|
]),
|
||||||
transition(':leave', [
|
query(':leave', animateChild()),
|
||||||
animate('0.5s ease-out', style({
|
group([
|
||||||
opacity: 0,
|
query(':leave', [
|
||||||
transform: 'translateY(100%)'
|
animate('300ms ease-out', style({ left: '100%'}))
|
||||||
}))
|
]),
|
||||||
|
query(':enter', [
|
||||||
|
animate('300ms ease-out', style({ left: '0%'}))
|
||||||
|
])
|
||||||
|
]),
|
||||||
|
query(':enter', animateChild()),
|
||||||
])
|
])
|
||||||
]);
|
]);
|
||||||
|
@ -1,16 +1,31 @@
|
|||||||
/* Second Heroes version */
|
/* Second Heroes version */
|
||||||
// #docregion
|
// #docregion
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
// #docregion animation-imports
|
||||||
|
import { RouterOutlet } from '@angular/router';
|
||||||
|
import { slideInAnimation } from './animations';
|
||||||
|
// #enddocregion animation-imports
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
|
// #docregion template
|
||||||
template: `
|
template: `
|
||||||
<h1>Angular Router</h1>
|
<h1>Angular Router</h1>
|
||||||
<nav>
|
<nav>
|
||||||
<a routerLink="/crisis-center" routerLinkActive="active">Crisis Center</a>
|
<a routerLink="/crisis-center" routerLinkActive="active">Crisis Center</a>
|
||||||
<a routerLink="/heroes" routerLinkActive="active">Heroes</a>
|
<a routerLink="/heroes" routerLinkActive="active">Heroes</a>
|
||||||
</nav>
|
</nav>
|
||||||
<router-outlet></router-outlet>
|
<div [@routeAnimation]="getAnimationData(routerOutlet)">
|
||||||
`
|
<router-outlet #routerOutlet="outlet"></router-outlet>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
animations: [ slideInAnimation ]
|
||||||
|
// #enddocregion template
|
||||||
})
|
})
|
||||||
export class AppComponent { }
|
// #docregion function-binding
|
||||||
|
export class AppComponent {
|
||||||
|
getAnimationData(outlet: RouterOutlet) {
|
||||||
|
return outlet && outlet.activatedRouteData && outlet.activatedRouteData['animation'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #enddocregion function-binding
|
||||||
|
@ -14,7 +14,9 @@ import { Component } from '@angular/core';
|
|||||||
// #enddocregion contact-link
|
// #enddocregion contact-link
|
||||||
</nav>
|
</nav>
|
||||||
// #docregion outlets
|
// #docregion outlets
|
||||||
<router-outlet></router-outlet>
|
<div [@routeAnimation]="getAnimationData(routerOutlet)">
|
||||||
|
<router-outlet #routerOutlet="outlet"></router-outlet>
|
||||||
|
</div>
|
||||||
<router-outlet name="popup"></router-outlet>
|
<router-outlet name="popup"></router-outlet>
|
||||||
// #enddocregion outlets
|
// #enddocregion outlets
|
||||||
`
|
`
|
||||||
|
@ -12,7 +12,9 @@ import { Component } from '@angular/core';
|
|||||||
<a routerLink="/admin" routerLinkActive="active">Admin</a>
|
<a routerLink="/admin" routerLinkActive="active">Admin</a>
|
||||||
<a [routerLink]="[{ outlets: { popup: ['compose'] } }]">Contact</a>
|
<a [routerLink]="[{ outlets: { popup: ['compose'] } }]">Contact</a>
|
||||||
</nav>
|
</nav>
|
||||||
<router-outlet></router-outlet>
|
<div [@routeAnimation]="getAnimationData(routerOutlet)">
|
||||||
|
<router-outlet #routerOutlet="outlet"></router-outlet>
|
||||||
|
</div>
|
||||||
<router-outlet name="popup"></router-outlet>
|
<router-outlet name="popup"></router-outlet>
|
||||||
`
|
`
|
||||||
// #enddocregion template
|
// #enddocregion template
|
||||||
|
@ -14,7 +14,9 @@ import { Component } from '@angular/core';
|
|||||||
<a routerLink="/login" routerLinkActive="active">Login</a>
|
<a routerLink="/login" routerLinkActive="active">Login</a>
|
||||||
<a [routerLink]="[{ outlets: { popup: ['compose'] } }]">Contact</a>
|
<a [routerLink]="[{ outlets: { popup: ['compose'] } }]">Contact</a>
|
||||||
</nav>
|
</nav>
|
||||||
<router-outlet></router-outlet>
|
<div [@routeAnimation]="getAnimationData(routerOutlet)">
|
||||||
|
<router-outlet #routerOutlet="outlet"></router-outlet>
|
||||||
|
</div>
|
||||||
<router-outlet name="popup"></router-outlet>
|
<router-outlet name="popup"></router-outlet>
|
||||||
`
|
`
|
||||||
// #enddocregion template
|
// #enddocregion template
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
// #docplaster
|
// #docplaster
|
||||||
// #docregion
|
// #docregion
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
import { RouterOutlet } from '@angular/router';
|
||||||
|
import { slideInAnimation } from './animations';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
@ -14,10 +16,16 @@ import { Component } from '@angular/core';
|
|||||||
<a routerLink="/login" routerLinkActive="active">Login</a>
|
<a routerLink="/login" routerLinkActive="active">Login</a>
|
||||||
<a [routerLink]="[{ outlets: { popup: ['compose'] } }]">Contact</a>
|
<a [routerLink]="[{ outlets: { popup: ['compose'] } }]">Contact</a>
|
||||||
</nav>
|
</nav>
|
||||||
<router-outlet></router-outlet>
|
<div [@routeAnimation]="getAnimationData(routerOutlet)">
|
||||||
|
<router-outlet #routerOutlet="outlet"></router-outlet>
|
||||||
|
</div>
|
||||||
<router-outlet name="popup"></router-outlet>
|
<router-outlet name="popup"></router-outlet>
|
||||||
`
|
`,
|
||||||
|
animations: [ slideInAnimation ]
|
||||||
// #enddocregion template
|
// #enddocregion template
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
|
getAnimationData(outlet: RouterOutlet) {
|
||||||
|
return outlet && outlet.activatedRouteData && outlet.activatedRouteData['animation'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,18 +2,11 @@
|
|||||||
import { Component, HostBinding } from '@angular/core';
|
import { Component, HostBinding } from '@angular/core';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
|
|
||||||
import { slideInDownAnimation } from './animations';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './compose-message.component.html',
|
templateUrl: './compose-message.component.html',
|
||||||
styles: [ ':host { position: relative; bottom: 10%; }' ],
|
styles: [ ':host { position: relative; bottom: 10%; }' ]
|
||||||
animations: [ slideInDownAnimation ]
|
|
||||||
})
|
})
|
||||||
export class ComposeMessageComponent {
|
export class ComposeMessageComponent {
|
||||||
@HostBinding('@routeAnimation') routeAnimation = true;
|
|
||||||
@HostBinding('style.display') display = 'block';
|
|
||||||
@HostBinding('style.position') position = 'absolute';
|
|
||||||
|
|
||||||
details: string;
|
details: string;
|
||||||
message: string;
|
message: string;
|
||||||
sending = false;
|
sending = false;
|
||||||
|
@ -5,7 +5,6 @@ import { ActivatedRoute, Router, ParamMap } from '@angular/router';
|
|||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { switchMap } from 'rxjs/operators';
|
import { switchMap } from 'rxjs/operators';
|
||||||
|
|
||||||
import { slideInDownAnimation } from '../animations';
|
|
||||||
import { Crisis, CrisisService } from './crisis.service';
|
import { Crisis, CrisisService } from './crisis.service';
|
||||||
import { DialogService } from '../dialog.service';
|
import { DialogService } from '../dialog.service';
|
||||||
|
|
||||||
@ -25,14 +24,9 @@ import { DialogService } from '../dialog.service';
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
styles: ['input {width: 20em}'],
|
styles: ['input {width: 20em}']
|
||||||
animations: [ slideInDownAnimation ]
|
|
||||||
})
|
})
|
||||||
export class CrisisDetailComponent implements OnInit {
|
export class CrisisDetailComponent implements OnInit {
|
||||||
@HostBinding('@routeAnimation') routeAnimation = true;
|
|
||||||
@HostBinding('style.display') display = 'block';
|
|
||||||
@HostBinding('style.position') position = 'absolute';
|
|
||||||
|
|
||||||
crisis: Crisis;
|
crisis: Crisis;
|
||||||
editName: string;
|
editName: string;
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@ import { Component, OnInit, HostBinding } from '@angular/core';
|
|||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
import { slideInDownAnimation } from '../animations';
|
|
||||||
import { Crisis } from './crisis.service';
|
import { Crisis } from './crisis.service';
|
||||||
import { DialogService } from '../dialog.service';
|
import { DialogService } from '../dialog.service';
|
||||||
|
|
||||||
@ -24,14 +23,9 @@ import { DialogService } from '../dialog.service';
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
styles: ['input {width: 20em}'],
|
styles: ['input {width: 20em}']
|
||||||
animations: [ slideInDownAnimation ]
|
|
||||||
})
|
})
|
||||||
export class CrisisDetailComponent implements OnInit {
|
export class CrisisDetailComponent implements OnInit {
|
||||||
@HostBinding('@routeAnimation') routeAnimation = true;
|
|
||||||
@HostBinding('style.display') display = 'block';
|
|
||||||
@HostBinding('style.position') position = 'absolute';
|
|
||||||
|
|
||||||
crisis: Crisis;
|
crisis: Crisis;
|
||||||
editName: string;
|
editName: string;
|
||||||
|
|
||||||
|
@ -7,8 +7,6 @@ import { Component, OnInit, HostBinding } from '@angular/core';
|
|||||||
import { Router, ActivatedRoute, ParamMap } from '@angular/router';
|
import { Router, ActivatedRoute, ParamMap } from '@angular/router';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
import { slideInDownAnimation } from '../animations';
|
|
||||||
|
|
||||||
import { Hero, HeroService } from './hero.service';
|
import { Hero, HeroService } from './hero.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -26,16 +24,9 @@ import { Hero, HeroService } from './hero.service';
|
|||||||
<button (click)="gotoHeroes(hero)">Back</button>
|
<button (click)="gotoHeroes(hero)">Back</button>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`
|
||||||
animations: [ slideInDownAnimation ]
|
|
||||||
})
|
})
|
||||||
export class HeroDetailComponent implements OnInit {
|
export class HeroDetailComponent implements OnInit {
|
||||||
// #docregion host-bindings
|
|
||||||
@HostBinding('@routeAnimation') routeAnimation = true;
|
|
||||||
@HostBinding('style.display') display = 'block';
|
|
||||||
@HostBinding('style.position') position = 'absolute';
|
|
||||||
// #enddocregion host-bindings
|
|
||||||
|
|
||||||
hero$: Observable<Hero>;
|
hero$: Observable<Hero>;
|
||||||
|
|
||||||
// #docregion ctor
|
// #docregion ctor
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
// #docregion
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
|
|
||||||
|
import { HeroListComponent } from './hero-list.component';
|
||||||
|
import { HeroDetailComponent } from './hero-detail.component';
|
||||||
|
|
||||||
|
const heroesRoutes: Routes = [
|
||||||
|
{ path: 'heroes', component: HeroListComponent, data: { animation: 'heroes' } },
|
||||||
|
{ path: 'hero/:id', component: HeroDetailComponent, data: { animation: 'hero' } }
|
||||||
|
];
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
RouterModule.forChild(heroesRoutes)
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
RouterModule
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class HeroRoutingModule { }
|
||||||
|
// #enddocregion
|
@ -8,8 +8,8 @@ import { HeroDetailComponent } from './hero-detail.component';
|
|||||||
const heroesRoutes: Routes = [
|
const heroesRoutes: Routes = [
|
||||||
{ path: 'heroes', redirectTo: '/superheroes' },
|
{ path: 'heroes', redirectTo: '/superheroes' },
|
||||||
{ path: 'hero/:id', redirectTo: '/superhero/:id' },
|
{ path: 'hero/:id', redirectTo: '/superhero/:id' },
|
||||||
{ path: 'superheroes', component: HeroListComponent },
|
{ path: 'superheroes', component: HeroListComponent, data: { animation: 'heroes' } },
|
||||||
{ path: 'superhero/:id', component: HeroDetailComponent }
|
{ path: 'superhero/:id', component: HeroDetailComponent, data: { animation: 'hero' } }
|
||||||
];
|
];
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -2171,8 +2171,7 @@ The optional `foo` route parameter is harmless and continues to be ignored.
|
|||||||
### Adding animations to the routed component
|
### Adding animations to the routed component
|
||||||
The heroes feature module is almost complete, but what is a feature without some smooth transitions?
|
The heroes feature module is almost complete, but what is a feature without some smooth transitions?
|
||||||
|
|
||||||
This section shows you how to add some [animations](guide/animations)
|
This section shows you how to add some [animations](guide/animations) to the `HeroDetailComponent`.
|
||||||
to the `HeroDetailComponent`.
|
|
||||||
|
|
||||||
First import `BrowserAnimationsModule`:
|
First import `BrowserAnimationsModule`:
|
||||||
|
|
||||||
@ -2180,6 +2179,11 @@ First import `BrowserAnimationsModule`:
|
|||||||
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
|
Next, add a `data` object to the routes for `HeroListComponent` and `HeroDetailComponent`. Transitions are based on `states` and you'll use the `animation` data from the route to provide a named animation `state` for the transitions.
|
||||||
|
|
||||||
|
<code-example path="router/src/app/heroes/heroes-routing.module.2.ts" title="src/app/heroes/heroes-routing.module.ts (animation data)">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
Create an `animations.ts` file in the root `src/app/` folder. The contents look like this:
|
Create an `animations.ts` file in the root `src/app/` folder. The contents look like this:
|
||||||
@ -2189,53 +2193,40 @@ Create an `animations.ts` file in the root `src/app/` folder. The contents look
|
|||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
This file does the following:
|
This file does the following:
|
||||||
|
|
||||||
* Imports the animation symbols that build the animation triggers, control state, and manage transitions between states.
|
* Imports the animation symbols that build the animation triggers, control state, and manage transitions between states.
|
||||||
|
|
||||||
* Exports a constant named `slideInDownAnimation` set to an animation trigger named *`routeAnimation`*;
|
* Exports a constant named `slideInAnimation` set to an animation trigger named *`routeAnimation`*;
|
||||||
animated components will refer to this name.
|
|
||||||
|
|
||||||
* Specifies the _wildcard state_ , `*`, that matches any animation state that the route component is in.
|
* Defines one *transition* when switching back and forth from the `heroes` and `hero` routes to ease the component in from the left of the screen as it enters the application view (`:enter`), the other to animate the component to the right as it leaves the application view (`:leave`).
|
||||||
|
|
||||||
* Defines two *transitions*, one to ease the component in from the left of the screen as it enters the application view (`:enter`),
|
You could also create more transitions for other routes. This trigger is sufficient for the current milestone.
|
||||||
the other to animate the component down as it leaves the application view (`:leave`).
|
|
||||||
|
|
||||||
You could create more triggers with different transitions for other route components. This trigger is sufficient for the current milestone.
|
Back in the `AppComponent`, import the `RouterOutlet` token from the `@angular/router` package and the `slideInDownAnimation` from `'./animations.ts`.
|
||||||
|
|
||||||
|
<code-example path="router/src/app/app.component.2.ts" linenums="false" title="src/app/app.component.ts (animation imports)" region="animation-imports">
|
||||||
Back in the `HeroDetailComponent`, import the `slideInDownAnimation` from `'./animations.ts`.
|
|
||||||
Add the `HostBinding` decorator to the imports from `@angular/core`; you'll need it in a moment.
|
|
||||||
|
|
||||||
Add an `animations` array to the `@Component` metadata's that contains the `slideInDownAnimation`.
|
|
||||||
|
|
||||||
Then add three `@HostBinding` properties to the class to set the animation and styles for the route component's element.
|
|
||||||
|
|
||||||
<code-example path="router/src/app/heroes/hero-detail.component.ts" linenums="false" title="src/app/heroes/hero-detail.component.ts (host bindings)" region="host-bindings">
|
|
||||||
|
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
|
In order to use the routable animations, you'll need to wrap the `RouterOutlet` inside an element. You'll
|
||||||
|
use the `@routeAnimation` trigger and bind it to the element.
|
||||||
|
|
||||||
|
For the `@routeAnimation` transitions to key off states, you'll need to provide it with the `data` from the `ActivatedRoute`. The `RouterOutlet` is exposed as an `outlet` template variable, so you bind a reference to the router outlet. A variable of `routerOutlet` is an ideal choice.
|
||||||
|
|
||||||
The `'@routeAnimation'` passed to the first `@HostBinding` matches
|
Add an `animations` array to the `@Component` metadata's that contains the `slideInDownAnimation`.
|
||||||
the name of the `slideInDownAnimation` _trigger_, `routeAnimation`.
|
|
||||||
Set the `routeAnimation` property to `true` because you only care about the `:enter` and `:leave` states.
|
|
||||||
|
|
||||||
The other two `@HostBinding` properties style the display and position of the component.
|
<code-example path="router/src/app/app.component.2.ts" linenums="false" title="src/app/app.component.ts (router outlet)" region="template">
|
||||||
|
|
||||||
The `HeroDetailComponent` will ease in from the left when routed to and will slide down when navigating away.
|
</code-example>
|
||||||
|
|
||||||
|
The `@routeAnimation` property is bound to the `getAnimationData` with the provided `routerOutlet` reference, so you'll need to define that function in the `AppComponent`. The `getAnimationData` function returns the animation property from the `data` provided through the `ActivatedRoute`. The `animation` property matches the `transition` names you used in the `slideDownAnimation` defined in `animations.ts`.
|
||||||
|
|
||||||
<div class="alert is-helpful">
|
<code-example path="router/src/app/app.component.2.ts" linenums="false" title="src/app/app.component.ts (router outlet)" region="function-binding">
|
||||||
|
|
||||||
|
</code-example>
|
||||||
|
|
||||||
|
When switching between the two routes, the `HeroDetailComponent` and `HeroListComponent` will ease in from the left when routed to and will slide to the right when navigating away.
|
||||||
Applying route animations to individual components works for a simple demo, but in a real life app,
|
|
||||||
it is better to animate routes based on _route paths_.
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -2250,7 +2241,7 @@ You've learned how to do the following:
|
|||||||
* Navigate imperatively from one component to another.
|
* Navigate imperatively from one component to another.
|
||||||
* Pass information along in route parameters and subscribe to them in the component.
|
* Pass information along in route parameters and subscribe to them in the component.
|
||||||
* Import the feature area NgModule into the `AppModule`.
|
* Import the feature area NgModule into the `AppModule`.
|
||||||
* Apply animations to the route component.
|
* Applying routable animations based on the page.
|
||||||
|
|
||||||
After these changes, the folder structure looks like this:
|
After these changes, the folder structure looks like this:
|
||||||
|
|
||||||
@ -2355,7 +2346,7 @@ Here are the relevant files for this version of the sample application.
|
|||||||
|
|
||||||
<code-tabs>
|
<code-tabs>
|
||||||
|
|
||||||
<code-pane title="app.component.ts" path="router/src/app/app.component.1.ts">
|
<code-pane title="app.component.ts" path="router/src/app/app.component.2.ts">
|
||||||
|
|
||||||
</code-pane>
|
</code-pane>
|
||||||
|
|
||||||
@ -2383,7 +2374,7 @@ Here are the relevant files for this version of the sample application.
|
|||||||
|
|
||||||
</code-pane>
|
</code-pane>
|
||||||
|
|
||||||
<code-pane title="heroes-routing.module.ts" path="router/src/app/heroes/heroes-routing.module.1.ts">
|
<code-pane title="heroes-routing.module.ts" path="router/src/app/heroes/heroes-routing.module.2.ts">
|
||||||
|
|
||||||
</code-pane>
|
</code-pane>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user