Merge remote-tracking branch 'remotes/angular.io/master'

# Conflicts:
#	public/docs/ts/latest/_data.json
#	public/docs/ts/latest/cheatsheet.jade
#	public/news.jade
This commit is contained in:
Zhimin YE (Rex) 2016-06-16 09:03:59 +01:00
commit e8a462435c
74 changed files with 1695 additions and 203 deletions

View File

@ -378,7 +378,7 @@ gulp.task('help', taskListing.withFilters(function(taskName) {
// requires admin access because it adds symlinks
gulp.task('add-example-boilerplate', function() {
var realPath = path.join(EXAMPLES_PATH, '/node_modules');
var nodeModulesPaths = getNodeModulesPaths(EXAMPLES_PATH);
var nodeModulesPaths = excludeDartPaths(getNodeModulesPaths(EXAMPLES_PATH));
nodeModulesPaths.forEach(function(linkPath) {
gutil.log("symlinking " + linkPath + ' -> ' + realPath)
@ -670,7 +670,10 @@ gulp.task('lint', function() {
'!./public/docs/_examples/**/node_modules/**/*',
'!./public/docs/_examples/_protractor/**/*',
'!./public/docs/_examples/**/typings/**/*',
'!./public/docs/_examples/**/typings-ng1/**/*'
'!./public/docs/_examples/**/typings-ng1/**/*',
// temporary until codelyzer is fixed mgechev/codelyzer#60
'!./public/docs/_examples/animations/ts/app/hero.service.ts'
])
.pipe(tslint({
rulesDirectory: ['node_modules/codelyzer'],

View File

@ -0,0 +1,296 @@
/// <reference path='../_protractor/e2e.d.ts' />
/**
* The tests here basically just checking that the end styles
* of each animation are in effect.
*
* Relies on the Angular 2 testability only becoming stable once
* animation(s) have finished.
*
* Ideally we'd use https://developer.mozilla.org/en-US/docs/Web/API/Document/getAnimations
* but they're not supported in Chrome at the moment. The upcoming nganimate polyfill
* may also add some introspection support.
*/
describe('Animation Tests', () => {
const INACTIVE_COLOR = 'rgba(238, 238, 238, 1)';
const ACTIVE_COLOR = 'rgba(207, 216, 220, 1)';
const NO_TRANSFORM_MATRIX_REGEX = /matrix\(1,\s*0,\s*0,\s*1,\s*0,\s*0\)/;
beforeEach(() => {
browser.get('');
});
describe('basic states', () => {
let host: protractor.ElementFinder;
beforeEach(() => {
host = element(by.css('hero-list-basic'));
});
it('animates between active and inactive', () => {
addHero();
let li = host.element(by.css('li'));
expect(getScaleX(li)).toBe(1.0);
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
li.click();
browser.driver.sleep(300);
expect(getScaleX(li)).toBe(1.1);
expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR);
li.click();
browser.driver.sleep(300);
expect(getScaleX(li)).toBe(1.0);
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
});
});
describe('styles inline in transitions', () => {
let host: protractor.ElementFinder;
beforeEach(function() {
host = element(by.css('hero-list-inline-styles'));
});
it('are not kept after animation', () => {
addHero();
let li = host.element(by.css('li'));
li.click();
browser.driver.sleep(300);
expect(getScaleX(li)).toBe(1.0);
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
});
});
describe('combined transition syntax', () => {
let host: protractor.ElementFinder;
beforeEach(() => {
host = element(by.css('hero-list-combined-transitions'));
});
it('animates between active and inactive', () => {
addHero();
let li = host.element(by.css('li'));
expect(getScaleX(li)).toBe(1.0);
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
li.click();
browser.driver.sleep(300);
expect(getScaleX(li)).toBe(1.1);
expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR);
li.click();
browser.driver.sleep(300);
expect(getScaleX(li)).toBe(1.0);
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
});
});
describe('two-way transition syntax', () => {
let host: protractor.ElementFinder;
beforeEach(() => {
host = element(by.css('hero-list-twoway'));
});
it('animates between active and inactive', () => {
addHero();
let li = host.element(by.css('li'));
expect(getScaleX(li)).toBe(1.0);
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
li.click();
browser.driver.sleep(300);
expect(getScaleX(li)).toBe(1.1);
expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR);
li.click();
browser.driver.sleep(300);
expect(getScaleX(li)).toBe(1.0);
expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR);
});
});
describe('enter & leave', () => {
let host: protractor.ElementFinder;
beforeEach(() => {
host = element(by.css('hero-list-enter-leave'));
});
it('adds and removes element', () => {
addHero();
let li = host.element(by.css('li'));
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
removeHero();
expect(li.isPresent()).toBe(false);
});
});
describe('enter & leave & states', () => {
let host: protractor.ElementFinder;
beforeEach(function() {
host = element(by.css('hero-list-enter-leave-states'));
});
it('adds and removes and animates between active and inactive', () => {
addHero();
let li = host.element(by.css('li'));
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
li.click();
browser.driver.sleep(300);
expect(getScaleX(li)).toBe(1.1);
li.click();
browser.driver.sleep(300);
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
removeHero();
expect(li.isPresent()).toBe(false);
});
});
describe('auto style calc', () => {
let host: protractor.ElementFinder;
beforeEach(function() {
host = element(by.css('hero-list-auto'));
});
it('adds and removes element', () => {
addHero();
let li = host.element(by.css('li'));
expect(li.getCssValue('height')).toBe('50px');
removeHero();
expect(li.isPresent()).toBe(false);
});
});
describe('different timings', () => {
let host: protractor.ElementFinder;
beforeEach(() => {
host = element(by.css('hero-list-timings'));
});
it('adds and removes element', () => {
addHero();
let li = host.element(by.css('li'));
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
expect(li.getCssValue('opacity')).toMatch('1');
removeHero();
expect(li.isPresent()).toBe(false);
});
});
describe('multiple keyframes', () => {
let host: protractor.ElementFinder;
beforeEach(() => {
host = element(by.css('hero-list-multistep'));
});
it('adds and removes element', () => {
addHero();
let li = host.element(by.css('li'));
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
expect(li.getCssValue('opacity')).toMatch('1');
removeHero();
expect(li.isPresent()).toBe(false);
});
});
describe('parallel groups', () => {
let host: protractor.ElementFinder;
beforeEach(() => {
host = element(by.css('hero-list-groups'));
});
it('adds and removes element', () => {
addHero();
let li = host.element(by.css('li'));
expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX);
expect(li.getCssValue('opacity')).toMatch('1');
removeHero();
expect(li.isPresent()).toBe(false);
});
});
function addHero() {
element(by.buttonText('Add hero')).click();
browser.driver.sleep(500);
}
function removeHero() {
element(by.buttonText('Remove hero')).click();
browser.driver.sleep(500);
}
function getScaleX(el: protractor.ElementFinder) {
return protractor.promise.all([
getBoundingClientWidth(el),
getOffsetWidth(el)
]).then(function([clientWidth, offsetWidth]) {
return clientWidth / offsetWidth;
});
}
function getBoundingClientWidth(el: protractor.ElementFinder): protractor.promise.Promise<number> {
return browser.executeScript(
'return arguments[0].getBoundingClientRect().width',
el.getWebElement()
);
}
function getOffsetWidth(el: protractor.ElementFinder): protractor.promise.Promise<number> {
return browser.executeScript(
'return arguments[0].offsetWidth',
el.getWebElement()
);
}
});

View File

@ -0,0 +1 @@
**/*.js

View File

@ -0,0 +1,46 @@
import {
Component,
Input,
trigger,
state,
style,
animate,
transition
} from '@angular/core';
import { Heroes } from './hero.service';
@Component({
moduleId: module.id,
selector: 'hero-list-auto',
// #docregion template
template: `
<ul>
<li *ngFor="let hero of heroes"
@shrinkOut="'in'">
{{hero.name}}
</li>
</ul>
`,
// #enddocregion template
styleUrls: ['hero-list.component.css'],
/* When the element leaves (transition "in => void" occurs),
* get the element's current computed height and animate
* it down to 0.
*/
// #docregion animationdef
animations: [
trigger('shrinkOut', [
state('in', style({height: '*'})),
transition('* => void', [
style({height: '*'}),
animate(250, style({height: 0}))
])
])
]
// #enddocregion animationdef
})
export class HeroListAutoComponent {
@Input() heroes: Heroes;
}

View File

@ -0,0 +1,69 @@
// #docplaster
// #docregion
// #docregion imports
import {
Component,
Input,
trigger,
state,
style,
transition,
animate
} from '@angular/core';
// #enddocregion imports
import { Heroes } from './hero.service';
@Component({
moduleId: module.id,
selector: 'hero-list-basic',
// #enddocregion
/* The click event calls hero.toggleState(), which
* causes the state of that hero to switch from
* active to inactive or vice versa.
*/
// #docregion
// #docregion template
template: `
<ul>
<li *ngFor="let hero of heroes"
@heroState="hero.state"
(click)="hero.toggleState()">
{{hero.name}}
</li>
</ul>
`,
// #enddocregion template
styleUrls: ['hero-list.component.css'],
// #enddocregion
/**
* Define two states, "inactive" and "active", and the end
* styles that apply whenever the element is in those states.
* Then define animations for transitioning between the states,
* one in each direction
*/
// #docregion
// #docregion animationdef
animations: [
trigger('heroState', [
// #docregion states
state('inactive', style({
backgroundColor: '#eee',
transform: 'scale(1)'
})),
state('active', style({
backgroundColor: '#cfd8dc',
transform: 'scale(1.1)'
})),
// #enddocregion states
// #docregion transitions
transition('inactive => active', animate('100ms ease-in')),
transition('active => inactive', animate('100ms ease-out'))
// #enddocregion transitions
])
]
// #enddocregion animationdef
})
export class HeroListBasicComponent {
@Input() heroes: Heroes;
}

View File

@ -0,0 +1,58 @@
// #docregion
// #docregion imports
import {
Component,
Input,
trigger,
state,
style,
transition,
animate
} from '@angular/core';
// #enddocregion imports
import { Heroes } from './hero.service';
@Component({
moduleId: module.id,
selector: 'hero-list-combined-transitions',
// #docregion template
template: `
<ul>
<li *ngFor="let hero of heroes"
@heroState="hero.state"
(click)="hero.toggleState()">
{{hero.name}}
</li>
</ul>
`,
// #enddocregion template
styleUrls: ['hero-list.component.css'],
/*
* Define two states, "inactive" and "active", and the end
* styles that apply whenever the element is in those states.
* Then define an animated transition between these two
* states, in *both* directions.
*/
// #docregion animationdef
animations: [
trigger('heroState', [
state('inactive', style({
backgroundColor: '#eee',
transform: 'scale(1)'
})),
state('active', style({
backgroundColor: '#cfd8dc',
transform: 'scale(1.1)'
})),
// #docregion transitions
transition('inactive => active, active => inactive',
animate('100ms ease-out'))
// #enddocregion transitions
])
]
// #enddocregion animationdef
})
export class HeroListCombinedTransitionsComponent {
@Input() heroes: Heroes;
}

View File

@ -0,0 +1,62 @@
import {
Component,
Input,
trigger,
state,
style,
animate,
transition
} from '@angular/core';
import { Heroes } from './hero.service';
@Component({
moduleId: module.id,
selector: 'hero-list-enter-leave-states',
// #docregion template
template: `
<ul>
<li *ngFor="let hero of heroes"
(click)="hero.toggleState()"
@heroState="hero.state">
{{hero.name}}
</li>
</ul>
`,
// #enddocregion template
styleUrls: ['hero-list.component.css'],
/* The elements here have two possible states based
* on the hero state, "active", or "inactive". We animate
* six transitions: Between the two states in both directions,
* and between each state and void. With this we can animate
* the enter and leave of elements differently based on which
* state they are in when they are added and removed.
*/
// #docregion animationdef
animations: [
trigger('heroState', [
state('inactive', style({transform: 'translateX(0) scale(1)'})),
state('active', style({transform: 'translateX(0) scale(1.1)'})),
transition('inactive => active', animate('100ms ease-in')),
transition('active => inactive', animate('100ms ease-out')),
transition('void => inactive', [
style({transform: 'translateX(-100%) scale(1)'}),
animate(100)
]),
transition('inactive => void', [
animate(100, style({transform: 'translateX(100%) scale(1)'}))
]),
transition('void => active', [
style({transform: 'translateX(0) scale(0)'}),
animate(200)
]),
transition('active => void', [
animate(200, style({transform: 'translateX(0) scale(0)'}))
])
])
]
// #enddocregion animationdef
})
export class HeroListEnterLeaveStatesComponent {
@Input() heroes: Heroes;
}

View File

@ -0,0 +1,50 @@
import {
Component,
Input,
trigger,
state,
style,
animate,
transition
} from '@angular/core';
import { Heroes } from './hero.service';
@Component({
moduleId: module.id,
selector: 'hero-list-enter-leave',
// #docregion template
template: `
<ul>
<li *ngFor="let hero of heroes"
@flyInOut="'in'">
{{hero.name}}
</li>
</ul>
`,
// #enddocregion template
styleUrls: ['hero-list.component.css'],
/* The element here always has the state "in" when it
* is present. We animate two transitions: From void
* to in and from in to void, to achieve an animated
* enter and leave transition. The element enters from
* the left and leaves to the right using translateX.
*/
// #docregion animationdef
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%)'}))
])
])
]
// #enddocregion animationdef
})
export class HeroListEnterLeaveComponent {
@Input() heroes: Heroes;
}

View File

@ -0,0 +1,79 @@
import {
Component,
Input,
trigger,
state,
style,
animate,
transition,
group
} from '@angular/core';
import { Heroes } from './hero.service';
@Component({
moduleId: module.id,
selector: 'hero-list-groups',
template: `
<ul>
<li *ngFor="let hero of heroes"
@flyInOut="'in'">
{{hero.name}}
</li>
</ul>
`,
styleUrls: ['hero-list.component.css'],
styles: [`
li {
padding: 0 !important;
text-align: center;
}
`],
/* The element here always has the state "in" when it
* is present. We animate two transitions: From void
* to in and from in to void, to achieve an animated
* enter and leave transition.
*
* The transitions have *parallel group* that allow
* animating several properties at the same time but
* with different timing configurations. On enter
* (void => *) we start the opacity animation 0.1s
* earlier than the translation/width animation.
* On leave (* => void) we do the opposite -
* the translation/width animation begins immediately
* and the opacity animation 0.1s later.
*/
// #docregion animationdef
animations: [
trigger('flyInOut', [
state('in', style({width: 120, transform: 'translateX(0)', opacity: 1})),
transition('void => *', [
style({width: 10, transform: 'translateX(50px)', opacity: 0}),
group([
animate('0.3s 0.1s ease', style({
transform: 'translateX(0)',
width: 120
})),
animate('0.3s ease', style({
opacity: 1
}))
])
]),
transition('* => void', [
group([
animate('0.3s ease', style({
transform: 'translateX(50px)',
width: 10
})),
animate('0.3s 0.2s ease', style({
opacity: 0
}))
])
])
])
]
// #enddocregion animationdef
})
export class HeroListGroupsComponent {
@Input() heroes: Heroes;
}

View File

@ -0,0 +1,59 @@
// #docregion
// #docregion imports
import {
Component,
Input,
trigger,
style,
transition,
animate
} from '@angular/core';
// #enddocregion imports
import { Heroes } from './hero.service';
@Component({
moduleId: module.id,
selector: 'hero-list-inline-styles',
// #docregion template
template: `
<ul>
<li *ngFor="let hero of heroes"
@heroState="hero.state"
(click)="hero.toggleState()">
{{hero.name}}
</li>
</ul>
`,
// #enddocregion template
styleUrls: ['hero-list.component.css'],
/**
* Define two states, "inactive" and "active", and the end
* styles that apply whenever the element is in those states.
* Then define an animation for the inactive => active transition.
* This animation has no end styles, but only styles that are
* defined inline inside the transition and thus are only kept
* as long as the animation is running.
*/
// #docregion animationdef
animations: [
trigger('heroState', [
// #docregion transitions
transition('inactive => active', [
style({
backgroundColor: '#cfd8dc',
transform: 'scale(1.3)'
}),
animate('80ms ease-in', style({
backgroundColor: '#eee',
transform: 'scale(1)'
}))
]),
// #enddocregion transitions
])
]
// #enddocregion animationdef
})
export class HeroListInlineStylesComponent {
@Input() heroes: Heroes;
}

View File

@ -0,0 +1,57 @@
import {
Component,
Input,
trigger,
state,
style,
animate,
transition,
keyframes
} from '@angular/core';
import { Heroes } from './hero.service';
@Component({
moduleId: module.id,
selector: 'hero-list-multistep',
template: `
<ul>
<li *ngFor="let hero of heroes"
@flyInOut="'in'">
{{hero.name}}
</li>
</ul>
`,
styleUrls: ['hero-list.component.css'],
/* The element here always has the state "in" when it
* is present. We animate two transitions: From void
* to in and from in to void, to achieve an animated
* enter and leave transition. Each transition is
* defined in terms of multiple keyframes, to give it
* a bounce effect.
*/
// #docregion animationdef
animations: [
trigger('flyInOut', [
state('in', style({transform: 'translateX(0)'})),
transition('void => *', [
animate(300, keyframes([
style({opacity: 0, transform: 'translateX(-100%)', offset: 0}),
style({opacity: 1, transform: 'translateX(15px)', offset: 0.3}),
style({opacity: 1, transform: 'translateX(0)', offset: 1.0})
]))
]),
transition('* => void', [
animate(300, keyframes([
style({opacity: 1, transform: 'translateX(0)', offset: 0}),
style({opacity: 1, transform: 'translateX(-15px)', offset: 0.7}),
style({opacity: 0, transform: 'translateX(100%)', offset: 1.0})
]))
])
])
]
// #enddocregion animationdef
})
export class HeroListMultistepComponent {
@Input() heroes: Heroes;
}

View File

@ -0,0 +1,57 @@
import {
Component,
Input,
trigger,
state,
style,
animate,
transition
} from '@angular/core';
import { Heroes } from './hero.service';
@Component({
moduleId: module.id,
selector: 'hero-list-timings',
template: `
<ul>
<li *ngFor="let hero of heroes"
@flyInOut="'in'"
(click)="hero.toggleState()">
{{hero.name}}
</li>
</ul>
`,
styleUrls: ['hero-list.component.css'],
/* The element here always has the state "in" when it
* is present. We animate two transitions: From void
* to in and from in to void, to achieve an animated
* enter and leave transition. The element enters from
* the left and leaves to the right using translateX,
* and fades in/out using opacity. We use different easings
* for enter and leave.
*/
// #docregion animationdef
animations: [
trigger('flyInOut', [
state('in', style({opacity: 1, transform: 'translateX(0)'})),
transition('void => *', [
style({
opacity: 0,
transform: 'translateX(-100%)'
}),
animate('0.2s ease-in')
]),
transition('* => void', [
animate('0.2s 10 ease-out', style({
opacity: 0,
transform: 'translateX(100%)'
}))
])
])
]
// #enddocregion animationdef
})
export class HeroListTimingsComponent {
@Input() heroes: Heroes;
}

View File

@ -0,0 +1,57 @@
// #docregion
// #docregion imports
import {
Component,
Input,
trigger,
state,
style,
transition,
animate
} from '@angular/core';
// #enddocregion imports
import { Heroes } from './hero.service';
@Component({
moduleId: module.id,
selector: 'hero-list-twoway',
// #docregion template
template: `
<ul>
<li *ngFor="let hero of heroes"
@heroState="hero.state"
(click)="hero.toggleState()">
{{hero.name}}
</li>
</ul>
`,
// #enddocregion template
styleUrls: ['hero-list.component.css'],
/*
* Define two states, "inactive" and "active", and the end
* styles that apply whenever the element is in those states.
* Then define an animated transition between these two
* states, in *both* directions.
*/
// #docregion animationdef
animations: [
trigger('heroState', [
state('inactive', style({
backgroundColor: '#eee',
transform: 'scale(1)'
})),
state('active', style({
backgroundColor: '#cfd8dc',
transform: 'scale(1.1)'
})),
// #docregion transitions
transition('inactive <=> active', animate('100ms ease-out'))
// #enddocregion transitions
])
]
// #enddocregion animationdef
})
export class HeroListTwowayComponent {
@Input() heroes: Heroes;
}

View File

@ -0,0 +1,27 @@
ul {
list-style-type: none;
padding: 0;
}
li {
display: block;
width: 120px;
line-height: 50px;
padding: 0 10px;
box-sizing: border-box;
background-color: #eee;
border-radius: 4px;
margin: 10px;
cursor: pointer;
overflow: hidden;
white-space: nowrap;
}
.active {
background-color: #cfd8dc;
transform: scale(1.1);
}
.inactive {
background-color: #eee;
transform: scale(1);
}

View File

@ -0,0 +1,115 @@
import { Component } from '@angular/core';
import { Heroes } from './hero.service';
import { HeroListBasicComponent } from './hero-list-basic.component';
import { HeroListInlineStylesComponent } from './hero-list-inline-styles.component';
import { HeroListEnterLeaveComponent } from './hero-list-enter-leave.component';
import { HeroListEnterLeaveStatesComponent } from './hero-list-enter-leave-states.component';
import { HeroListCombinedTransitionsComponent } from './hero-list-combined-transitions.component';
import { HeroListTwowayComponent } from './hero-list-twoway.component';
import { HeroListAutoComponent } from './hero-list-auto.component';
import { HeroListGroupsComponent } from './hero-list-groups.component';
import { HeroListMultistepComponent } from './hero-list-multistep.component';
import { HeroListTimingsComponent } from './hero-list-timings.component';
@Component({
selector: 'hero-team-builder',
template: `
<div class="buttons">
<button [disabled]="!heroes.canAdd()" (click)="heroes.add()">Add hero</button>
<button [disabled]="!heroes.canRemove()" (click)="heroes.remove()">Remove hero</button>
</div>
<div class="columns">
<div class="column">
<h4>Basic State</h4>
<p>Switch between active/inactive on click.</p>
<hero-list-basic [heroes]=heroes></hero-list-basic>
</div>
<div class="column">
<h4>Styles inline in transitions</h4>
<p>Animated effect on click, no persistend end styles.</p>
<hero-list-inline-styles [heroes]=heroes></hero-list-inline-styles>
</div>
<div class="column">
<h4>Combined transition syntax</h4>
<p>Switch between active/inactive on click. Define just one transition used in both directions.</p>
<hero-list-combined-transitions [heroes]=heroes></hero-list-combined-transitions>
</div>
<div class="column">
<h4>Two-way transition syntax</h4>
<p>Switch between active/inactive on click. Define just one transition used in both directions using the <=> syntax.</p>
<hero-list-twoway [heroes]=heroes></hero-list-twoway>
</div>
<div class="column">
<h4>Enter & Leave</h4>
<p>Enter and leave animations using the void state.</p>
<hero-list-enter-leave [heroes]=heroes></hero-list-enter-leave>
</div>
</div>
<div class="columns">
<div class="column">
<h4>Enter & Leave & States</h4>
<p>
Enter and leave animations combined with active/inactive state animations.
Different enter and leave transitions depending on state.
</p>
<hero-list-enter-leave-states [heroes]=heroes></hero-list-enter-leave-states>
</div>
<div class="column">
<h4>Auto Style Calc</h4>
<p>Leave animation from the current computed height using the auto-style value *.</p>
<hero-list-auto [heroes]=heroes></hero-list-auto>
</div>
<div class="column">
<h4>Different Timings</h4>
<p>Enter and leave animations with different easings, ease-in for enter, ease-out for leave.</p>
<hero-list-timings [heroes]=heroes></hero-list-timings>
</div>
<div class="column">
<h4>Multiple Keyframes</h4>
<p>Enter and leave animations with three keyframes in each, to give the transition some bounce.</p>
<hero-list-multistep [heroes]=heroes></hero-list-multistep>
</div>
<div class="column">
<h4>Parallel Groups</h4>
<p>Enter and leave animations with multiple properties animated in parallel with different timings.</p>
<hero-list-groups [heroes]=heroes></hero-list-groups>
</div>
</div>
`,
styles: [`
.buttons {
text-align: center;
}
button {
padding: 1.5em 3em;
}
.columns {
display: flex;
flex-direction: row;
}
.column {
flex: 1;
padding: 10px;
}
.column p {
min-height: 6em;
}
`],
directives: [
HeroListBasicComponent,
HeroListInlineStylesComponent,
HeroListCombinedTransitionsComponent,
HeroListTwowayComponent,
HeroListEnterLeaveComponent,
HeroListEnterLeaveStatesComponent,
HeroListAutoComponent,
HeroListTimingsComponent,
HeroListMultistepComponent,
HeroListGroupsComponent
],
providers: [Heroes]
})
export class HeroTeamBuilderComponent {
constructor(private heroes: Heroes) { }
}

View File

@ -0,0 +1,54 @@
import { Injectable } from '@angular/core';
class Hero {
constructor(public name: string,
public state = 'inactive') {
}
toggleState() {
this.state = (this.state === 'active' ? 'inactive' : 'active');
}
}
let ALL_HEROES = [
'Wolverine',
'Magneto',
'Emma Frost',
'Thing',
'Kitty Pryde',
'Nightcrawler',
'Juggernaut',
'Beast',
'Captain America',
'Spider-Man',
'Puck',
'Alex Wilder',
'Doctor Strange'
].map(name => new Hero(name));
@Injectable()
export class Heroes implements Iterable<Hero> {
currentHeroes: Hero[] = [];
[Symbol.iterator]() {
return this.currentHeroes.values();
}
canAdd() {
return this.currentHeroes.length < ALL_HEROES.length;
}
canRemove() {
return this.currentHeroes.length > 0;
}
add() {
this.currentHeroes.push(ALL_HEROES[this.currentHeroes.length]);
}
remove() {
this.currentHeroes.splice(this.currentHeroes.length - 1, 1);
}
}

View File

@ -0,0 +1,5 @@
import { bootstrap } from '@angular/platform-browser-dynamic';
import { HeroTeamBuilderComponent } from './hero-team-builder.component';
bootstrap(HeroTeamBuilderComponent);

View File

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Animations</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!-- Polyfill for Web Animations -->
<script src="https://npmcdn.com/web-animations-js@2.2.1"></script>
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<h1 style="visibility: hidden;">External H1 Title for E2E test</h1>
<hero-team-builder></hero-team-builder>
<button style="visibility: hidden;">External button for E2E test</button>
<ul style="visibility: hidden;">
<li>External list for E2E test</li>
</ul>
</body>
</html>

View File

@ -0,0 +1,7 @@
{
"description": "Angular 2 Animations",
"files":[
"!**/*.d.ts",
"!**/*.js"
]
}

View File

@ -10,6 +10,9 @@ dependencies:
dart_to_js_script_rewriter: ^1.0.1
transformers:
- angular2:
platform_directives: 'package:angular2/common.dart#CORE_DIRECTIVES'
platform_directives:
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes:
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: web/main.dart
- dart_to_js_script_rewriter

View File

@ -10,6 +10,9 @@ dependencies:
dart_to_js_script_rewriter: ^1.0.1
transformers:
- angular2:
platform_directives: 'package:angular2/common.dart#CORE_DIRECTIVES'
platform_directives:
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes:
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: web/main.dart
- dart_to_js_script_rewriter

View File

@ -10,6 +10,9 @@ dependencies:
dart_to_js_script_rewriter: ^1.0.1
transformers:
- angular2:
platform_directives: 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_directives:
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes:
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: web/main.dart
- dart_to_js_script_rewriter

View File

@ -10,8 +10,10 @@ dependencies:
dart_to_js_script_rewriter: ^1.0.1
transformers:
- angular2:
platform_directives: 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes: 'package:angular2/common.dart#COMMON_PIPES'
platform_directives:
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes:
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: web/main.dart
- dart_to_js_script_rewriter
dev_dependencies:

View File

@ -10,6 +10,9 @@ dependencies:
dart_to_js_script_rewriter: ^1.0.1
transformers:
- angular2:
platform_directives: 'package:angular2/common.dart#CORE_DIRECTIVES'
platform_directives:
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes:
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: web/main.dart
- dart_to_js_script_rewriter

View File

@ -11,7 +11,9 @@ dependencies:
transformers:
- angular2:
platform_directives:
- 'package:angular2/common.dart#CORE_DIRECTIVES'
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
- 'package:angular2/common.dart#FORM_DIRECTIVES'
platform_pipes:
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: web/main.dart
- dart_to_js_script_rewriter

View File

@ -10,6 +10,9 @@ dependencies:
dart_to_js_script_rewriter: ^1.0.1
transformers:
- angular2:
platform_directives: 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_directives:
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes:
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: web/main.dart
- dart_to_js_script_rewriter

View File

@ -11,7 +11,8 @@ dependencies:
transformers:
- angular2:
platform_directives:
- 'package:angular2/common.dart#CORE_DIRECTIVES'
- 'package:angular2/common.dart#FORM_DIRECTIVES'
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes:
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: web/main.dart
- dart_to_js_script_rewriter

View File

@ -34,7 +34,7 @@
"@angular/router": "2.0.0-rc.2",
"@angular/router-deprecated": "2.0.0-rc.2",
"@angular/upgrade": "2.0.0-rc.2",
"angular2-in-memory-web-api": "0.0.11",
"angular2-in-memory-web-api": "0.0.12",
"bootstrap": "^3.3.6",
"core-js": "^2.4.0",
"reflect-metadata": "^0.1.3",

View File

@ -10,7 +10,9 @@ dependencies:
dart_to_js_script_rewriter: ^1.0.1
transformers:
- angular2:
platform_directives: 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes: 'package:angular2/common.dart#COMMON_PIPES'
platform_directives:
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes:
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: web/main.dart
- dart_to_js_script_rewriter

View File

@ -1,6 +1,4 @@
# #docplaster
# #docregion
# #docregion no-rewriter
name: angular2_getting_started
description: QuickStart
version: 0.0.1
@ -9,11 +7,12 @@ environment:
dependencies:
angular2: 2.0.0-beta.17
browser: ^0.10.0
# #enddocregion no-rewriter
dart_to_js_script_rewriter: ^1.0.1
# #docregion no-rewriter
transformers:
- angular2:
platform_directives:
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes:
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: web/main.dart
# #enddocregion no-rewriter
- dart_to_js_script_rewriter

View File

@ -22,7 +22,7 @@
"rxjs": "5.0.0-beta.6",
"zone.js": "0.6.12",
"angular2-in-memory-web-api": "0.0.11",
"angular2-in-memory-web-api": "0.0.12",
"bootstrap": "^3.3.6"
},
"devDependencies": {

View File

@ -27,7 +27,7 @@
"rxjs": "5.0.0-beta.6",
"zone.js": "^0.6.12",
"angular2-in-memory-web-api": "0.0.11",
"angular2-in-memory-web-api": "0.0.12",
"bootstrap": "^3.3.6"
},
"devDependencies": {

View File

@ -40,7 +40,7 @@
// Bundled (~40 requests):
function packUmd(pkgName) {
packages['@angular/'+pkgName] = { main: pkgName + '.umd.js', defaultExtension: 'js' };
packages['@angular/'+pkgName] = { main: '/bundles/' + pkgName + '.umd.js', defaultExtension: 'js' };
}
// Most environments should use UMD; some (Karma) need the individual index files

View File

@ -16,10 +16,10 @@ dependencies:
transformers:
- angular2:
platform_directives:
- 'package:angular2/common.dart#CORE_DIRECTIVES'
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes:
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: 'web/main.dart'
entry_points: web/main.dart
resolved_identifiers:
BrowserClient: 'package:http/browser_client.dart'
- dart_to_js_script_rewriter

View File

@ -10,6 +10,9 @@ dependencies:
dart_to_js_script_rewriter: ^1.0.1
transformers:
- angular2:
platform_directives: 'package:angular2/common.dart#CORE_DIRECTIVES'
platform_directives:
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes:
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: web/main.dart
- dart_to_js_script_rewriter

View File

@ -10,9 +10,10 @@ dependencies:
dart_to_js_script_rewriter: ^1.0.1
transformers:
- angular2:
platform_pipes: 'package:angular2/common.dart#COMMON_PIPES'
platform_directives:
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
- 'package:angular2/common.dart#FORM_DIRECTIVES'
platform_pipes:
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: web/main.dart
- dart_to_js_script_rewriter

View File

@ -1,5 +1,6 @@
# #docregion
name: angular2_tour_of_heroes
description: Tour of Heroes
version: 0.0.1
environment:
sdk: '>=1.13.0 <2.0.0'
@ -10,7 +11,8 @@ dependencies:
transformers:
- angular2:
platform_directives:
- package:angular2/common.dart#COMMON_DIRECTIVES
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes:
- package:angular2/common.dart#COMMON_PIPES
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: web/main.dart
- dart_to_js_script_rewriter

View File

@ -1,4 +1,6 @@
# #docregion
name: angular2_tour_of_heroes
description: Tour of Heroes
version: 0.0.1
environment:
sdk: '>=1.13.0 <2.0.0'
@ -9,7 +11,8 @@ dependencies:
transformers:
- angular2:
platform_directives:
- package:angular2/common.dart#COMMON_DIRECTIVES
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes:
- package:angular2/common.dart#COMMON_PIPES
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: web/main.dart
- dart_to_js_script_rewriter

View File

@ -1,4 +1,6 @@
# #docregion
name: angular2_tour_of_heroes
description: Tour of Heroes
version: 0.0.1
environment:
sdk: '>=1.13.0 <2.0.0'
@ -9,7 +11,8 @@ dependencies:
transformers:
- angular2:
platform_directives:
- package:angular2/common.dart#COMMON_DIRECTIVES
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes:
- package:angular2/common.dart#COMMON_PIPES
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: web/main.dart
- dart_to_js_script_rewriter

View File

@ -8,7 +8,6 @@ import 'hero.dart';
import 'hero_detail_component.dart';
// #docregion hero-service-import
import 'hero_service.dart';
// #enddocregion hero-service-import
@Component(
@ -92,17 +91,17 @@ class AppComponent implements OnInit {
AppComponent(this._heroService);
// #docregion get-heroes
getHeroes() async {
// #docregion get-heroes
Future<Null> getHeroes() async {
heroes = await _heroService.getHeroes();
}
// #enddocregion get-heroes
// #enddocregion get-heroes
ngOnInit() {
void ngOnInit() {
getHeroes();
}
onSelect(Hero hero) {
void onSelect(Hero hero) {
selectedHero = hero;
}
}

View File

@ -5,9 +5,7 @@ import 'package:angular2/core.dart';
// #enddocregion on-init
import 'hero.dart';
import 'hero_detail_component.dart';
// #docregion hero-service-import
import 'hero_service_1.dart';
// #enddocregion hero-service-import
// Testable but never shown
@Component(
@ -21,7 +19,7 @@ import 'hero_service_1.dart';
directives: const [HeroDetailComponent],
// #docregion providers
providers: const [HeroService])
// #enddocregion providers
// #enddocregion providers
// #docregion on-init
class AppComponent implements OnInit {
// #enddocregion on-init
@ -38,27 +36,25 @@ class AppComponent implements OnInit {
final HeroService _heroService;
AppComponent(this._heroService);
// #enddocregion ctor
// #docregion getHeroes
getHeroes() {
//#docregion get-heroes
void getHeroes() {
// #docregion get-heroes
heroes = _heroService.getHeroes();
// #enddocregion get-heroes
}
// #enddocregion getHeroes
// #docregion ng-on-init
// #docregion on-init
ngOnInit() {
// #docregion ng-on-init, on-init
void ngOnInit() {
// #enddocregion on-init
getHeroes();
// #docregion on-init
}
// #enddocregion on-init
// #enddocregion ng-on-init
// #enddocregion ng-on-init, on-init
onSelect(Hero hero) {
void onSelect(Hero hero) {
selectedHero = hero;
}
// #docregion on-init
}
// #enddocregion on-init

View File

@ -14,8 +14,8 @@ import 'hero.dart';
<input [(ngModel)]="hero.name" placeholder="name"/>
</div>
</div>
''',
inputs: const ['hero'])
''')
class HeroDetailComponent {
@Input()
Hero hero;
}

View File

@ -12,15 +12,15 @@ import 'mock_heroes.dart';
class HeroService {
// #docregion get-heroes
Future<List<Hero>> getHeroes() async => mockHeroes;
// #enddocregion get-heroes
// #enddocregion just-get-heroes
// #enddocregion get-heroes, just-get-heroes
// #enddocregion
// See the "Take it slow" appendix
// #docregion get-heroes-slowly
Future<List<Hero>> getHeroesSlowly() {
return new Future.delayed(const Duration(seconds: 2), () => mockHeroes);
}
// #enddocregion get-heroes-slowly
// #docregion
// #docregion just-get-heroes
}
// #enddocregion just-get-heroes
// #enddocregion

View File

@ -10,19 +10,13 @@ import 'mock_heroes.dart';
// #docregion getHeroes-stub
@Injectable()
class HeroService {
// #enddocregion getHeroes-stub
// #enddocregion empty-class
// #enddocregion final
// #enddocregion getHeroes-stub, empty-class, final
/*
// #docregion getHeroes-stub
// #docregion getHeroes-stub
List<Hero> getHeroes() {}
// #enddocregion getHeroes-stub
*/
// #docregion final
// #enddocregion getHeroes-stub
*/
// #docregion final
List<Hero> getHeroes() => mockHeroes;
// #docregion empty-class
// #docregion getHeroes-stub
// #docregion empty-class, getHeroes-stub
}
// #enddocregion getHeroes-stub
// #enddocregion empty-class
// #enddocregion final

View File

@ -13,4 +13,3 @@ final List<Hero> mockHeroes = [
new Hero(19, 'Magma'),
new Hero(20, 'Tornado')
];
// #enddocregion

View File

@ -1,4 +1,6 @@
# #docregion
name: angular2_tour_of_heroes
description: Tour of Heroes
version: 0.0.1
environment:
sdk: '>=1.13.0 <2.0.0'
@ -9,7 +11,8 @@ dependencies:
transformers:
- angular2:
platform_directives:
- package:angular2/common.dart#COMMON_DIRECTIVES
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes:
- package:angular2/common.dart#COMMON_PIPES
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: web/main.dart
- dart_to_js_script_rewriter

View File

@ -1,9 +1,7 @@
// #docregion pt1
import 'package:angular2/platform/browser.dart';
import 'package:angular2_tour_of_heroes/app_component.dart';
main() {
void main() {
bootstrap(AppComponent);
}
// #enddocregion pt1

View File

@ -1,9 +1,7 @@
// #docregion pt1
import 'package:angular2/platform/browser.dart';
import 'package:angular2_tour_of_heroes/app_component_1.dart';
main() {
void main() {
bootstrap(AppComponent);
}
// #enddocregion pt1

View File

@ -1,6 +1,6 @@
# #docregion
name: angular2_tour_of_heroes
description: Tour of Heroes 5
description: Tour of Heroes
version: 0.0.1
environment:
sdk: '>=1.13.0 <2.0.0'
@ -11,8 +11,8 @@ dependencies:
transformers:
- angular2:
platform_directives:
- package:angular2/common.dart#COMMON_DIRECTIVES
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes:
- package:angular2/common.dart#COMMON_PIPES
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: web/main.dart
- dart_to_js_script_rewriter

View File

@ -10,6 +10,9 @@ dependencies:
dart_to_js_script_rewriter: ^1.0.1
transformers:
- angular2:
platform_directives: 'package:angular2/common.dart#CORE_DIRECTIVES'
platform_directives:
- 'package:angular2/common.dart#COMMON_DIRECTIVES'
platform_pipes:
- 'package:angular2/common.dart#COMMON_PIPES'
entry_points: web/main.dart
- dart_to_js_script_rewriter

View File

@ -10,13 +10,13 @@
},
"license": "MIT",
"dependencies": {
"@angular/common": "2.0.0-rc.1",
"@angular/compiler": "2.0.0-rc.1",
"@angular/core": "2.0.0-rc.1",
"@angular/http": "2.0.0-rc.1",
"@angular/platform-browser": "2.0.0-rc.1",
"@angular/platform-browser-dynamic": "2.0.0-rc.1",
"@angular/router-deprecated": "2.0.0-rc.1",
"@angular/common": "2.0.0-rc.2",
"@angular/compiler": "2.0.0-rc.2",
"@angular/core": "2.0.0-rc.2",
"@angular/http": "2.0.0-rc.2",
"@angular/platform-browser": "2.0.0-rc.2",
"@angular/platform-browser-dynamic": "2.0.0-rc.2",
"@angular/router-deprecated": "2.0.0-rc.2",
"core-js": "^2.4.0",
"reflect-metadata": "0.1.2",
"rxjs": "5.0.0-beta.6",
@ -40,10 +40,10 @@
"rimraf": "^2.5.2",
"style-loader": "^0.13.1",
"ts-loader": "^0.8.1",
"typescript": "^1.8.9",
"typescript": "^1.8.10",
"typings": "^1.0.4",
"webpack": "^1.12.14",
"webpack": "^1.13.0",
"webpack-dev-server": "^1.14.1",
"webpack-merge": "^0.9.0"
"webpack-merge": "^0.14.0"
}
}

View File

@ -9,10 +9,5 @@
"removeComments": false,
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
},
"exclude": [
"node_modules",
"typings/main",
"typings/main.d.ts"
]
}
}

View File

@ -15,13 +15,13 @@
"tutorial": {
"icon": "list",
"title": "Tutorial",
"banner": "Angular 2 is currently in Beta."
"banner": "Angular 2 is currently in Release Candidate."
},
"guide": {
"icon": "list",
"title": "Developer Guides",
"banner": "Angular 2 is currently in Beta."
"banner": "Angular 2 is currently in Release Candidate."
},
"cookbook": {
@ -51,7 +51,7 @@
"resources": {
"icon": "play-circle-fill",
"title": "Angular Resources",
"banner": "Angular 2 is currently in Beta.",
"banner": "Angular 2 is currently in Release Candidate.",
"resources": true
},

View File

@ -1,6 +1,6 @@
- var base = current.path[4] ? '.' : './guide';
.banner.grid-fluid
p.text-body.c10 This cheat sheet is provisional and may change. Angular 2 is currently in Beta.
p.text-body.c10 This cheat sheet is provisional and may change. Angular 2 is currently in Release Candidate.
article(class="l-content-small grid-fluid docs-content")
.cheatsheet

View File

@ -13,7 +13,7 @@ include ../_util-fns
It also makes it easier to unit test the component with a mock service.
Because data services are invariably asynchronous,
we'll finish the chapter with a promise-based version of the data service.
we'll finish the chapter with a **!{_Promise}**-based version of the data service.
p Run the #[+liveExampleLink2('', 'toh-4')] for this part.
@ -35,6 +35,7 @@ p Run the #[+liveExampleLink2('', 'toh-4')] for this part.
.children
.file index.html
.file main.dart
.file styles.css
.file pubspec.yaml
:marked
### Keep the app compiling and running
@ -59,7 +60,7 @@ code-example(language="bash").
First, defining heroes is not the component's job.
Second, we can't easily share that list of heroes with other components and views.
We can refactor this hero data acquisition business to a single service that provides heroes and
We can refactor this hero data acquisition business to a single service that provides heroes, and
share that service with all components that need heroes.
### Create the HeroService
@ -67,12 +68,12 @@ code-example(language="bash").
.l-sub-section
:marked
We've adopted a convention in which we spell the name of a service in lowercase followed by `_service`.
If the service name were multi-word, we'd spell the base filename with lower underscore case (AKA "snake_case").
If the service name were multi-word, we'd spell the base filename in lower underscore case (also called [snake_case](../guide/glossary.html#!#snake_case)).
The `SpecialSuperHeroService` would be defined in the `special_super_hero_service.dart` file.
:marked
We name the class `HeroService`.
+makeExample('toh-4/dart/lib/hero_service_1.dart', 'empty-class', 'hero_service.dart (class)')(format=".")
+makeExample('toh-4/dart/lib/hero_service_1.dart', 'empty-class', 'lib/hero_service.dart (starting point)')(format=".")
:marked
### Injectable Services
@ -91,7 +92,7 @@ code-example(language="bash").
:marked
### Getting Heroes
Add a `getHeroes` method stub.
+makeExample('toh-4/dart/lib/hero_service_1.dart', 'getHeroes-stub', 'hero_service.dart (getHeroes stub)')(format=".")
+makeExample('toh-4/dart/lib/hero_service_1.dart', 'getHeroes-stub', 'lib/hero_service.dart (getHeroes stub)')(format=".")
:marked
We're holding back on the implementation for a moment to make an important point.
@ -109,31 +110,31 @@ code-example(language="bash").
We already have mock `Hero` data sitting in the `AppComponent`. It doesn't belong there. It doesn't belong *here* either.
We'll move the mock data to its own file.
Cut the the `mockHeroes` list from `app_component.dart` and paste it to a new file in the `lib` folder named `mock_heroes.dart`.
Cut the `mockHeroes` list from `app_component.dart` and paste it to a new file in the `lib` folder named `mock_heroes.dart`.
We copy the `import 'hero.dart'` statement as well because the heroes list uses the `Hero` class.
+makeExample('toh-4/dart/lib/mock_heroes.dart', null, 'mock_heroes.dart (Heroes list)')
+makeExample('toh-4/dart/lib/mock_heroes.dart', null, 'lib/mock_heroes.dart')
:marked
Meanwhile, back in `app_component.dart` where we cut away the `mockHeroes` list,
we leave behind an uninitialized `heroes` property:
+makeExample('toh-4/dart/lib/app_component_1.dart', 'heroes-prop', 'app_component.dart (heroes property)')(format=".")
+makeExample('toh-4/dart/lib/app_component_1.dart', 'heroes-prop', 'lib/app_component.dart (heroes property)')(format=".")
:marked
### Return Mocked Heroes
Back in the `HeroService` we import the mock `mockHeroes` and return it from the `getHeroes` method.
Our `HeroService` looks like this:
+makeExample('toh-4/dart/lib/hero_service_1.dart', 'final', 'hero_service.dart')(format=".")
+makeExample('toh-4/dart/lib/hero_service_1.dart', 'final', 'lib/hero_service.dart')(format=".")
:marked
### Use the Hero Service
We're ready to use the `HeroService` in other components starting with our `AppComponent`.
We begin, as usual, by importing the thing we want to use, the `HeroService`.
+makeExample('toh-4/dart/lib/app_component.dart', 'hero-service-import', 'app_component.dart (import HeroService)')(format=".")
+makeExcerpt('toh-4/dart/lib/app_component.dart', 'hero-service-import')
:marked
Importing the service allows us to *reference* it in our code.
How should the `AppComponent` acquire a runtime concrete `HeroService` instance?
### Do we *new* the *HeroService*? No way!
We could create a new instance of the `HeroService` with "new" like this:
We could create a new instance of the `HeroService` with `new` like this:
+makeExample('toh-4/dart/lib/app_component_1.dart', 'new-service')(format=".")
:marked
That's a bad idea for several reasons including
@ -143,7 +144,7 @@ code-example(language="bash").
we'll have to find every place we create the service and fix it.
Running around patching code is error prone and adds to the test burden.
* We create a new service each time we use "new".
* We create a new service each time we use `new`.
What if the service should cache heroes and share that cache with others?
We couldn't do that.
@ -166,7 +167,7 @@ code-example(language="bash").
1. We add to the component's `providers` metadata.
Here are the property and the constructor:
+makeExample('toh-4/dart/lib/app_component_1.dart', 'ctor', 'app_component.dart (constructor)')(format='.')
+makeExample('toh-4/dart/lib/app_component_1.dart', 'ctor', 'lib/app_component.dart (constructor)')(format='.')
:marked
The constructor does nothing except set the `_heroService`
property. The `HeroService` type of `_heroService`
@ -186,14 +187,14 @@ code-example(language="bash").
:marked
The *injector* does not know yet how to create a `HeroService`.
If we ran our code now, Angular would fail with an error:
code-example(format="." language="html").
code-example(format="nocode").
EXCEPTION: No provider for HeroService! (AppComponent -> HeroService)
:marked
We have to teach the *injector* how to make a `HeroService` by registering a `HeroService` **provider**.
Do that by adding the following `providers` parameter to the bottom of the component metadata
in the `@Component` annotation.
+makeExample('toh-4/dart/lib/app_component_1.dart', 'providers', 'app_component.dart (providing HeroService)')(format=".")
+makeExcerpt('toh-4/dart/lib/app_component_1.dart', 'providers')
:marked
The `providers` parameter tells Angular to create a fresh instance of the `HeroService` when it creates a new `AppComponent`.
The `AppComponent` can use that service to get heroes and so can every child component of its component tree.
@ -207,7 +208,7 @@ code-example(format="." language="html").
If the `HeroDetailComponent` needed its parent component's `HeroService`,
it would ask Angular to inject the service into its constructor which would look just like the one for `AppComponent`:
+makeExample('toh-4/dart/lib/app_component_1.dart', 'ctor', 'hero_detail_component.dart (constructor)')(format=".")
+makeExample('toh-4/dart/lib/app_component_1.dart', 'ctor', 'lib/hero_detail_component.dart (constructor)')(format=".")
:marked
The `HeroDetailComponent` must *not* repeat its parent's `providers` list! Guess [why](#shadow-provider).
@ -221,7 +222,7 @@ code-example(format="." language="html").
+makeExample('toh-4/dart/lib/app_component_1.dart', 'get-heroes')(format=".")
:marked
We don't really need a dedicated method to wrap one line. We write it anyway:
+makeExample('toh-4/dart/lib/app_component_1.dart', 'getHeroes', 'app_component.dart (getHeroes)')(format=".")
+makeExcerpt('toh-4/dart/lib/app_component_1.dart', 'getHeroes')
<a id="oninit"></a>
:marked
@ -248,18 +249,19 @@ code-example(format="." language="html").
Learn more about lifecycle hooks in the [Lifecycle Hooks](../guide/lifecycle-hooks.html) chapter.
:marked
Here's the essential outline for the `OnInit` interface:
+makeExample('toh-4/dart/lib/app_component_1.dart', 'on-init', 'app_component.dart (OnInit protocol)')(format=".")
+makeExample('toh-4/dart/lib/app_component_1.dart', 'on-init', 'lib/app_component.dart (ngOnInit stub)')(format=".")
:marked
We write an `ngOnInit` method with our initialization logic inside and leave it to Angular to call it
at the right time. In our case, we initialize by calling `getHeroes`.
+makeExample('toh-4/dart/lib/app_component_1.dart', 'ng-on-init', 'app_component.dart (OnInit protocol)')(format=".")
+makeExcerpt('toh-4/dart/lib/app_component_1.dart', 'ng-on-init')
:marked
Our application should be running as expected, showing a list of heroes and a hero detail view
when we click on a hero name.
We're getting closer. But something isn't quite right.
## Async Services and Futures
<a id="async"></a>
## Async Services and !{_Promise}
Our `HeroService` returns a list of mock heroes immediately.
Its `getHeroes` signature is synchronous
+makeExample('toh-4/dart/lib/app_component_1.dart', 'get-heroes')(format=".")
@ -273,42 +275,42 @@ code-example(format="." language="html").
We'll have to use some kind of asynchronous technique and that will change the signature of our `getHeroes` method.
We'll use *futures*.
We'll use *!{_Promise}s*.
### The Hero Service returns a future
### The Hero Service returns a !{_Promise}
We ask an asynchronous service to do some work and give us the result in the future.
The service does that work (somewhere) and eventually it updates the future with the results of the work or an error.
We ask an asynchronous service to do some work and give us the result in the !{_Promise}.
The service does that work (somewhere) and eventually it updates the !{_Promise} with the results of the work or an error.
.l-sub-section
:marked
We are simplifying. Learn about Futures in the tutorial
We are simplifying. Learn about !{_Promise}s in the tutorial
[Asynchronous Programming: Futures](https://www.dartlang.org/docs/tutorials/futures/).
:marked
Update the `HeroService` with this future-returning `getHeroes` method:
+makeExample('toh-4/dart/lib/hero_service.dart', 'get-heroes', 'hero_service.dart (getHeroes)')(format=".")
Update the `HeroService` with this !{_Promise}-returning `getHeroes` method:
+makeExample('toh-4/dart/lib/hero_service.dart', 'get-heroes', 'lib/hero_service.dart (excerpt)')(format=".")
:marked
We're still mocking the data. We're simulating the behavior of an ultra-fast, zero-latency server,
by returning a future that will quickly resolve with our mock heroes as the result.
by returning a !{_Promise} that will quickly resolve with our mock heroes as the result.
.l-sub-section
:marked
Marking the method's body with `async` makes the method immediately return a `Future` object.
That future later completes with the method's return value.
That !{_Promise} later completes with the method's return value.
For more information on async functions, see
[Declaring async functions](https://www.dartlang.org/docs/dart-up-and-running/ch02.html#async) in the Dart language tour.
:marked
### Act on the Futures
### Act on the !{_Promise}
Returning to the `AppComponent` and its `getHeroes` method, we see that it still looks like this:
+makeExample('toh-4/dart/lib/app_component_1.dart', 'getHeroes', 'app_component.dart (getHeroes - old)')(format=".")
+makeExample('toh-4/dart/lib/app_component_1.dart', 'getHeroes', 'lib/app_component.dart (getHeroes - old)')(format=".")
:marked
As a result of our change to `HeroService`, we're now setting `heroes` to a future rather than a list of heroes.
As a result of our change to `HeroService`, we're now setting `heroes` to a !{_Promise} rather than a list of heroes.
We have to change our implementation to *act on the future when it resolves*.
We can *await* the future to resolve, and then display the heroes:
+makeExample('toh-4/dart/lib/app_component.dart', 'get-heroes', 'app_component.dart (getHeroes - revised)')(format=".")
We have to change our implementation to *act on the !{_Promise} when it resolves*.
We can *await* for the !{_Promise} to resolve, and then display the heroes:
+makeExample('toh-4/dart/lib/app_component.dart', 'get-heroes', 'lib/app_component.dart (getHeroes - revised)')(format=".")
:marked
Our code waits until the future completes, and then
Our code waits until the !{_Promise} completes, and then
sets the component's `heroes` property to the list of heroes returned by the service. That's all there is to it!
Our app should still be running, still showing a list of heroes, and still
@ -334,6 +336,7 @@ code-example(format="." language="html").
.children
.file index.html
.file main.dart
.file styles.css
.file pubspec.yaml
:marked
Here are the code files we discussed in this chapter.
@ -351,11 +354,11 @@ code-example(format="." language="html").
## The Road Weve Travelled
Lets take stock of what weve built.
* We created a service class that can be shared by many components
* We used the `ngOnInit` Lifecycle Hook to get our heroes when our `AppComponent` activates
* We defined our `HeroService` as a provider for our `AppComponent`
* We created mock hero data and imported them into our service
* We designed our service to return a future and our component to get our data from the future
* We created a service class that can be shared by many components.
* We used the `ngOnInit` Lifecycle Hook to get our heroes when our `AppComponent` activates.
* We defined our `HeroService` as a provider for our `AppComponent`.
* We created mock hero data and imported them into our service.
* We designed our service to return a !{_Promise} and our component to get our data from the !{_Promise}.
### The Road Ahead
@ -373,10 +376,10 @@ code-example(format="." language="html").
We can simulate a slow connection.
Add the following `getHeroesSlowly` method to the `HeroService`:
+makeExample('toh-4/dart/lib/hero_service.dart', 'get-heroes-slowly', 'hero_service.dart (getHeroesSlowly)')(format=".")
+makeExample('toh-4/dart/lib/hero_service.dart', 'get-heroes-slowly', 'lib/hero_service.dart (getHeroesSlowly)')(format=".")
:marked
Like `getHeroes`, it also returns a future.
But this future waits 2 seconds before resolving the future with mock heroes.
Like `getHeroes`, it also returns a !{_Promise}.
But this !{_Promise} waits 2 seconds before resolving the !{_Promise} with mock heroes.
Back in the `AppComponent`, replace
`_heroService.getHeroes` with `_heroService.getHeroesSlowly`

View File

@ -15,13 +15,13 @@
"tutorial": {
"icon": "list",
"title": "Tutorial",
"banner": "Angular 2 is currently in Beta."
"banner": "Angular 2 is currently in Release Candidate."
},
"guide": {
"icon": "list",
"title": "Developer Guides",
"banner": "Angular 2 is currently in Beta."
"banner": "Angular 2 is currently in Release Candidate."
},
"cookbook": {
@ -51,7 +51,7 @@
"resources": {
"icon": "play-circle-fill",
"title": "Angular Resources",
"banner": "Angular 2 is currently in Beta.",
"banner": "Angular 2 is currently in Release Candidate.",
"resources": true
},

View File

@ -22,13 +22,13 @@
"tutorial": {
"icon": "list",
"title": "教程",
"banner": "Angular 2正处于Beta阶段。"
"banner": "Angular 2正处于候选版本阶段。"
},
"guide": {
"icon": "list",
"title": "开发指南",
"banner": "Angular 2正处于Beta阶段。"
"banner": "Angular 2正处于候选版本阶段。"
},
"cookbook": {
@ -58,7 +58,7 @@
"resources": {
"icon": "play-circle-fill",
"title": "Angular资源",
"banner": "Angular 2正处于Beta阶段",
"banner": "Angular 2正处于候选版本阶段",
"resources": true
},

View File

@ -1,7 +1,7 @@
- var base = current.path[4] ? '.' : './guide';
.banner
p.text-body This cheat sheet is provisional and may change. Angular 2 is currently in Beta.
p.text-body 本小抄是临时的将来可能改变。Angular 2目前还是Beta状态
p.text-body 本小抄是临时的将来可能改变。Angular 2目前在候选版本阶段
article(class="l-content-small grid-fluid docs-content")
.cheatsheet

View File

@ -63,6 +63,11 @@
"basics": true
},
"animations": {
"title": "Animations",
"intro": "A guide to Angular's animation system."
},
"attribute-directives": {
"title": "属性型指令",
"intro": "属性型指令把行为添加到现有元素上。"

View File

@ -0,0 +1,339 @@
include ../_util-fns
:marked
Motion is an important aspect in the design of modern web applications. We want our
user interfaces to have smooth transitions between states, and engaging animations
that call attention where it's needed. Well-designed animations can make a UI not only
more fun but also easier to use.
Angular's animation system gives us what we need to make the kinds of animations we want.
We can build animations that run with the same kind of native performance that we're used
to with pure CSS animations. But we can also have our animation logic tightly integrated
with the rest of our application code, where they can be easily triggered and controlled.
.alert.is-helpful
:marked
Angular animations are built on top of the standard [Web Animations API](https://w3c.github.io/web-animations/)
and they run natively on [browsers that support it](http://caniuse.com/#feat=web-animation).
For other browsers, a polyfill is required. Grab
[`web-animations.min.js` from here](https://github.com/web-animations/web-animations-js) and
add it to your page.
A more lightweight polyfill maintained by the Angular team is coming soon.
:marked
# Table of Contents
* [Quickstart Example: Transitioning Between Two States](#example-transitioning-between-states)
* [States and Transitions](#states-and-transitions)
* [Example: Entering and Leaving](#example-entering-and-leaving)
* [Example: Entering and Leaving from Different States](#example-entering-and-leaving-from-different-states)
* [Animatable Properties and Units](#animatable-properties-and-units)
* [Automatic Property Calculation](#automatic-property-calculation)
* [Animation Timing](#animation-timing)
* [Multi-Step Animations with Keyframes](#multi-step-animations-with-keyframes)
* [Parallel Animation Groups](#parallel-animation-groups)
.l-sub-section
:marked
The examples referenced in this chapter are available as a [live example](/resources/live-examples/animations/ts/plnkr.html).
a(id="example-transitioning-between-states")
.l-main-section
:marked
## Quickstart Example: Transitioning Between Two States
figure
img(src="/resources/images/devguide/animations/animation_basic_click.gif" alt="A simple transition animation" align="right" style="width:220px;margin-left:20px" )
:marked
Let's build a simple animation that transitions an element between two states
driven by a model attribute.
Animations are defined inside `@Component` metadata. Before we can add some, we need
to import a few animation-specific functions:
+makeExample('animations/ts/app/hero-list-basic.component.ts', 'imports')(format=".")
:marked
With these we can now define an *animation trigger* called `heroState` in the component
metadata. It has animated transitions between two states: `active` and `inactive`. When a
hero is active, we display a the element in slightly larger size and lighter color.
+makeExample('animations/ts/app/hero-list-basic.component.ts', 'animationdef')(format=".")
.alert.is-helpful
:marked
In this example we are defining animation styles (color and transform) inline in the
animation metadata. In an upcoming release of Angular, support will be added for pulling
the styles in from the component CSS stylesheet instead.
:marked
We now have an animation defined but it is not yet used anywhere. We can change that by
attaching it to one or more elements in the component's template using the "`@triggerName`"
syntax:
+makeExample('animations/ts/app/hero-list-basic.component.ts', 'template')(format=".")
:marked
Here we've applied the animation trigger to every element repeated by an `ngFor`. Each of
the repeated elements will animate independently. We're binding the value of the
attribute to the expression `hero.state`. We expect it to always be either `inactive`
or `active`, since that's what we have defined animation states for.
With this setup, an animated transition is shown whenever a hero object changes state!
Here's the full component implementation:
+makeExample('animations/ts/app/hero-list-basic.component.ts')
:marked
## States and Transitions
Angular animations are defined in terms of logical **states** and **transitions**
between states.
An animation state is a string value that we define in our application code. In the example
above we used the states `'active'` and `'inactive'` based on the logical state of
hero objects. The source of the state can be a simple object attribute as it was in this case,
or it can be a value computed in a method. The important thing is that we can read it into the
component's template.
We can define *styles* for each animation state:
+makeExample('animations/ts/app/hero-list-basic.component.ts', 'states')(format=".")
:marked
These `state` definitions specify the *end styles* of each state.
They are applied to the element once it has transitioned to that state, and will stay
*as long as it remains in that state*. In that sense, we are defining more than just
animations here. We're actually defining what styles the element has in different states.
Once we have states, we can define *transitions* between the states. Each transition
controls the timing of switching between one set of styles and the next:
+makeExample('animations/ts/app/hero-list-basic.component.ts', 'transitions')(format=".")
figure.image-display
img(src="/resources/images/devguide/animations/ng_animate_transitions_inactive_active.png" alt="In Angular animations we defines states and transitions between states" width="400")
:marked
If we have the same timing configuration for several transitions, we can combine
them into the same `transition` definition:
+makeExample('animations/ts/app/hero-list-combined-transitions.component.ts', 'transitions')(format=".")
:marked
When we have the same timing for both directions of a transition, as we do in the previous
example, we can use the `<=>` shorthand syntax:
+makeExample('animations/ts/app/hero-list-twoway.component.ts', 'transitions')(format=".")
:marked
Sometimes we have styles that we want to apply during an animation but not keep around
after it finishes. We can define such styles inline in the `transition`. In this example,
the element receives one set of styles immediately and is then animated to the next.
When the transition finishes, none of these styles will be kept because they're not
defined in a `state`.
+makeExample('animations/ts/app/hero-list-inline-styles.component.ts', 'transitions')(format=".")
:marked
### The wildcard state `*`
The `*` ("wildcard") state matches *any* animation state. This is useful for defining styles and
transitions that should apply regardless of which state the animation is in. For example:
* The `active => *` transition applies when the element's state changes from `active` to anything else.
* The `* => *` transition applies when *any* change between two states takes place.
figure.image-display
img(src="/resources/images/devguide/animations/ng_animate_transitions_inactive_active_wildcards.png" alt="The wildcard state can be used to match many different transitions at once" width="400")
:marked
### The `void` state
There's one special state called `void` that may apply to any animation. It applies
when the element is *not* attached to a view. This may be because it has not yet been
added or because it has been removed. The `void` state is useful for defining "enter" and
"leave" animations.
For example the `* => void` transition applies when the element leaves the view,
regardless of what state it was in before it left.
figure.image-display
img(src="/resources/images/devguide/animations/ng_animate_transitions_void_in.png" alt="The void state can be used for enter and leave transitions" width="400")
:marked
The wildcard state `*` also matches `void`.
## Example: Entering and Leaving
figure
img(src="/resources/images/devguide/animations/animation_enter_leave.gif" alt="Enter and leave animations" align="right" style="width:250px;" )
:marked
Using the `void` and `*` states we can define transitions that animate the
entering and leaving of elements:
* Enter: `void => *`
* Leave: `* => void`
+makeExample('animations/ts/app/hero-list-enter-leave.component.ts', 'animationdef')(format=".")
:marked
Note that in this case we have the styles applied to the void state directly in the
transition definitions, and not in a separate `state(void)` definition. We do this because
we want the transforms to be different on enter and leave: The element enters from the left
and leaves to the right.
## Example: Entering and Leaving from Different States
figure
img(src="/resources/images/devguide/animations/animation_enter_leave_states.gif" alt="Enter and leave animations combined with state animations" align="right" style="width:200px" )
:marked
We can also combine this animation with the earlier state transition animation by
using the hero state as the animation state. What this will let us do is configure
different transitions for entering and leaving based on what the state of the hero
is:
* Inactive hero enter: `void => inactive`
* Active hero enter: `void => active`
* Inactive hero leave: `active => void`
* Active hero leave: `inactive => void`
We now have fine-grained control over each transition:
figure.image-display
img(src="/resources/images/devguide/animations/ng_animate_transitions_inactive_active_void.png" alt="This example transitions between active, inactive, and void states" width="400")
+makeExample('animations/ts/app/hero-list-enter-leave-states.component.ts', 'animationdef')(format=".")
:marked
## Animatable Properties and Units
Since Angular's animation support builds on top of Web Animations, we can animate any property
that the browser considers *animatable*. This includes positions, sizes, transforms, colors,
borders and many others. The W3C maintains
[a list of animatable properties](https://www.w3.org/TR/css3-transitions/#animatable-properties).
For positional properties that have a numeric value, we can define a unit by providing
the value as a string with the appropriate suffix:
* `'50px'`
* `'3em'`
* `'100%'`
For most dimensinal properties we can also just define a number which is then assumed to be
in pixels:
* `50` is the same as saying `'50px'`
## Automatic Property Calculation
figure
img(src="/resources/images/devguide/animations/animation_auto.gif" alt="Animation with automated height calculation" align="right" style="width:220px;margin-left:20px" )
:marked
Sometimes the value of a dimensional style property that we want to
animate is not known until at runtime. For example, it is quite common for elements
to have widths and heights that depend on their content and the screen size. These
properties are often tricky to animate with CSS.
With Angular we can use a special `*` property value in these cases. What it means
is that the value of this property will be computed at runtime and then plugged into
the animation.
The "leave" animation in this example takes whatever height the element has before it
leaves and animates from that height to zero:
+makeExample('animations/ts/app/hero-list-auto.component.ts', 'animationdef')(format=".")
:marked
## Animation Timing
There are three timing properties we can tune for every animated transition:
The duration, the delay, and the easing function. They are all combined into
a single transition *timing string*.
### Duration
The duration controls how long the animation takes to run from start to finish.
We can define a duration in three ways:
* As a plain number, in milliseconds: `100`
* In a string, as milliseconds: `'100ms'`
* In a string, as seconds: `'0.1s'`
### Delay
The delay controls how long to wait after an animation triggers before the
transition actually begins. We can define one by adding it in the same string
following the duration. It also has the same format options as the duration:
* Wait for 100ms and then run for 200ms: `'0.2s 100ms'`
### Easing
The [easing function](http://easings.net/) controls how the animation accelerates
and decelerates during its runtime. For example, using an `ease-in` function means
the animation begins relatively slowly but then picks up speed as it progresses. We
can control the easing by adding it as a *third* value in the string after the duration
and the delay (or as the *second* value when there is no delay):
* Wait for 100ms and then run for 200ms, with easing: `'0.2s 100ms ease-out'`
* Run for 200ms, with easing: `'0.2s ease-in-out'`
figure
img(src="/resources/images/devguide/animations/animation_timings.gif" alt="Animations with specific timings" align="right" style="width:220px;margin-left:20px" )
:marked
### Example
Here are a couple of custom timings in action. Both "enter" and "leave" last for
200 milliseconds but they have different easings. The leave begins after a
slight delay:
+makeExample('animations/ts/app/hero-list-timings.component.ts', 'animationdef')(format=".")
:marked
## Multi-Step Animations with Keyframes
figure
img(src="/resources/images/devguide/animations/animation_multistep.gif" alt="Animations with some bounce implemented with keyframes" align="right" style="width:220px;margin-left:20px" )
:marked
With animation *keyframes* we can go beyond a simple transition between two
sets of styles to a more intricate animation that goes through one or more
intermediate styles in between.
For each keyframe, we can specify an *offset* that defines at which point
in the animation that keyframe applies. The offset is a number between zero,
which marks the beginning of the animation, and one, which marks the end.
In this example we add some "bounce" to our enter and leave animations with
keyframes:
+makeExample('animations/ts/app/hero-list-multistep.component.ts', 'animationdef')(format=".")
:marked
Note that the offsets are *not* defined in terms of absolute time. They are relative
measures from 0 to 1. The final timeline of the animation will based on the combination
of keyframe offsets, duration, delay, and easing.
Defining offsets for keyframes is optional. If we omit them, offsets with even
spacing are automatically assigned. For example, three keyframes without predefined
offsets will receive offsets `0`, `0.5`, and `1`.
:marked
## Parallel Animation Groups
figure
img(src="/resources/images/devguide/animations/animation_groups.gif" alt="Parallel animations with different timings, implemented with groups" align="right" style="width:220px;margin-left:20px" )
:marked
We've already seen how we can animate multiple style properties at the same time:
Just put all of them into the same `style()` definition!
But we may also want to configure different *timings* for animations that happen
in parallel. For example, we may want to animate two CSS properties but use a
different easing function for each one.
For this we can use animation *groups*. In this example we use groups both on
enter and leave so that we can use two different timing configurations. Both
are applied to the same element in parallel, but run independent of each other:
+makeExample('animations/ts/app/hero-list-groups.component.ts', 'animationdef')(format=".")
:marked
One group animates the element transform and width. The other animates the opacity.

View File

@ -210,6 +210,13 @@ block install-packages
code-example(language="sh").
npm install
.l-sub-section
:marked
The `typings` folder could not show up after `npm install`. If so, please install them manually.
code-example(language="sh").
npm run typings install
.alert.is-important
:marked
Scary <span style="color:red; font-weight: bold">error messages in red</span> may appear **during** install.

View File

@ -1,103 +1,92 @@
.grid-fluid.l-space-bottom-2
.c12.text-center
h3.text-headline.text-uppercase Core Team
h3.text-headline.text-uppercase 核心开发组
.clear
.grid-fluid
.c6
.article-card
.date April 19, 2016
.date 2016-04-19
.date June 15, 2016
.title
a(
target="_blank"
href="https://angularjs.blogspot.com/2016/04/angular-2-react-native.html"
) Angular 2 + React Native
p The Angular 2 and React Native story started last summer [...] we are now pleased to share a library to build your own React Native applications with Angular 2 for iOS and Android...
p Angular 2和React Native之间的故事开始于去年夏天 [...] 我们很高兴现在能共享同一个库以便使用Angular 2来构建你自己的React原生应用 —— 为iOS和Android ……
href="http://angularjs.blogspot.com/2016/06/rc2-now-available.html"
) RC2 Now Available
p Today were happy to announce that we are shipping Angular 2.0.0-rc2. This release includes 1. Animation Framework 2. Improvements to Forms 3. More than 100 community contributions...
.author
img(src="/resources/images/bios/marclaval.jpg")
.posted Guest posted by <b>Marc Laval</b>
img(src="/resources/images/bios/stephenfluin.jpg")
.posted Posted by <b>Stephen Fluin</b>
.c6
.article-card
.date March 30, 2016
.date 2016-03-30
.date June 9, 2016
.title
a(
target="_blank"
href="http://angularjs.blogspot.com/2016/03/code-reuse-in-angular-2-native-mobile.html"
) Code Reuse in Angular 2 Native Mobile Apps with NativeScript
a(
target="_blank"
href="http://angularjs.blogspot.com/2016/03/code-reuse-in-angular-2-native-mobile.html"
) 利用NativeScript在Angular 2原生移动应用中复用代码
p In this article, I'm going to show you how to create a single application with Angular 2 that can be rendered on the web, or rendered in a native mobile application with NativeScript. Here's what you can expect to learn...
p 在本文档中我们将展示如何利用Angular 2创建一个单一应用让它可以利用NativeScript在Web上或者在原生移动应用中渲染。这可能正是你想学的。
href="http://angularjs.blogspot.com/2016/06/improvements-coming-for-routing-in.html"
) Improvements Coming for Routing in Angular
p A little more than a month ago, we introduced a new router at ng-conf. Were grateful to have heard from many folks at ng-conf about flaws in this new design, so we are announcing...
.author
img(src="/resources/images/bios/shield-bio-placeholder.png")
.posted Guest posted by <b>Nathan Walker</b>
img(src="/resources/images/bios/stephenfluin.jpg")
.posted Posted by <b>Stephen Fluin</b>
.grid-fluid.l-space-bottom-2.l-space-top-4
.c12.text-center
h3.text-headline.text-uppercase Developer Community
h3.text-headline.text-uppercase 开发者社区
.clear
.grid-fluid
.c6
.article-card
.date May 13, 2016
.date June 14, 2016
.title
a(
target="_blank"
href="http://blog.thoughtram.io/angular/2016/05/13/angular-2-providers-using-map-literals.html"
) Angular 2 Providers using Map Literals
p Defining providers in Angular 2 is pretty easy and straight forward. Another, shorter syntax makes creating providers even more enjoyable. In this article we take a look at how to create providers using map literals...
href="http://blog.thoughtram.io/angular/2016/06/14/routing-in-angular-2-revisited.html"
) Routing in Angular 2 Revisited
p Just recently, the Angular team announced yet another version of the new router. Take a first look at the new and better APIs, touching on the most common scenarios...
.author
img(src="/resources/images/bios/pascalprecht.jpg")
.posted Posted by <b>Pascal Precht</b>
.c6
.article-card
.date May 10, 2016
.date June 13, 2016
.title
a(
target="_blank"
href="https://medium.com/@richavyas/aha-moments-from-ngconf-2016-part-1-angular-2-0-compile-cycle-6f462f68632e#.ch4tad4ou"
) Aha Moments from ngconf 2016 Part 1: Angular 2.0 Compile Cycle
p WebStorm can be a great playground for your new Angular 2 applications. In this blog post wed like to share with you some tips and tricks that we hope youll find useful ...
p WebStorm可以成为新的Angular 2应用的上佳游乐场。在这篇blog中我们很高兴共享一些提示和技巧 —— 但愿能给你一点帮助。
href="https://toddmotto.com/rewriting-angular-styleguide-angular-2"
) A new Angular 1.x ES2015 styleguide, the path to Angular 2
p Angular 1.x has changed vastly since the original styleguide, and ES6/ES2015 has now become a defacto standard. The new styleguide focuses on using ES2015, offering recommendations on tooling to use it today...
.author
img(src="/resources/images/bios/shield-bio-placeholder.png")
.posted Posted by <b>Richa Vyas</b>
.posted Posted by <b>Todd Motto</b>
.grid-fluid
.c6
.article-card
.date May 9, 2016
.date June 9, 2016
.title
a(
target="_blank"
href="https://scotch.io/bar-talk/the-best-news-from-angulars-ng-conf-2016"
) The Best News from Angulars ng-conf 2016
p ng-conf 2016 in Salt Lake City brought a lot of incredible announcements. Just like last year, let's recap the announcements and takeaways from this year's ng-conf...
href="https://medium.com/@urish/building-simon-with-angular2-iot-fceb78bb18e5"
) Building Simon with Angular2-IoT
p I thought it would be fun to see if I could make the same [Angular 2] control/logic code for both a web application and a physical, “Internet of Things” device....
.author
img(src="/resources/images/bios/shield-bio-placeholder.png")
.posted Posted by <b>Chris Sevilleja</b>
img(src="/resources/images/bios/angular-gde-bio-placeholder.png")
.posted Posted by <b>Uri Shaked</b>
.c6
.article-card
.date May 6, 2016
.date June 8, 2016
.title
a(
target="_blank"
href="https://www.joaogarin.com/blog/building-desktop-apps-with-angular2-and-electron"
) Building Desktop Apps with Angular2 and Electron
p Electron is a great open source tool from Github that allows you to leverage your Javascript skills to build Desktop apps for MacOS, Windows and Linux systems...
href="http://blog.thoughtram.io/angular/2016/06/08/component-relative-paths-in-angular-2.html"
) Component-Relative Paths in Angular 2
p Component-based development is Angular 2s most-loved feature. By now you should be familiar with using the @Component decorators to create components.\...
.author
img(src="/resources/images/bios/shield-bio-placeholder.png")
.posted Posted by <b>Joao Garin</b>
img(src="/resources/images/bios/thomas.jpg")
.posted Posted by <b>Thomas Burleson</b>
.grid-fluid.l-space-bottom-2.l-space-top-4
.c12.text-center
@ -116,11 +105,6 @@
class="twitter-follow-button"
data-show-count="false"
) Follow @angularjs
a(
href="http://twitter.com/angularjs"
class="twitter-follow-button"
data-show-count="false"
) 追随 @angularjs
p.
<a class="twitter-timeline" data-chrome="nofooter noborders noheader"
href="http://twitter.com/angularjs" data-widget-id="700150278465523713"></a>

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 805 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB