diff --git a/public/docs/_examples/architecture/dart/pubspec.yaml b/public/docs/_examples/architecture/dart/pubspec.yaml index 91057332e9..ae0dd30e42 100644 --- a/public/docs/_examples/architecture/dart/pubspec.yaml +++ b/public/docs/_examples/architecture/dart/pubspec.yaml @@ -5,7 +5,7 @@ version: 0.0.1 environment: sdk: '>=1.13.0 <2.0.0' dependencies: - angular2: 2.0.0-beta.14 + angular2: 2.0.0-beta.15 browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/attribute-directives/dart/pubspec.yaml b/public/docs/_examples/attribute-directives/dart/pubspec.yaml index dfc064388a..b38d0d31a1 100644 --- a/public/docs/_examples/attribute-directives/dart/pubspec.yaml +++ b/public/docs/_examples/attribute-directives/dart/pubspec.yaml @@ -5,7 +5,7 @@ version: 0.0.1 environment: sdk: '>=1.13.0 <2.0.0' dependencies: - angular2: 2.0.0-beta.14 + angular2: 2.0.0-beta.15 browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/dependency-injection/dart/pubspec.yaml b/public/docs/_examples/dependency-injection/dart/pubspec.yaml index 680ef9ac4c..8ebf580e73 100644 --- a/public/docs/_examples/dependency-injection/dart/pubspec.yaml +++ b/public/docs/_examples/dependency-injection/dart/pubspec.yaml @@ -5,7 +5,7 @@ version: 0.0.1 environment: sdk: '>=1.13.0 <2.0.0' dependencies: - angular2: 2.0.0-beta.14 + angular2: 2.0.0-beta.15 browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/displaying-data/dart/pubspec.yaml b/public/docs/_examples/displaying-data/dart/pubspec.yaml index df1db78658..d4f309f79f 100644 --- a/public/docs/_examples/displaying-data/dart/pubspec.yaml +++ b/public/docs/_examples/displaying-data/dart/pubspec.yaml @@ -5,7 +5,7 @@ version: 0.0.1 environment: sdk: '>=1.13.0 <2.0.0' dependencies: - angular2: 2.0.0-beta.14 + angular2: 2.0.0-beta.15 browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/forms/dart/pubspec.yaml b/public/docs/_examples/forms/dart/pubspec.yaml index 7f8b04464b..056dd6cda7 100644 --- a/public/docs/_examples/forms/dart/pubspec.yaml +++ b/public/docs/_examples/forms/dart/pubspec.yaml @@ -5,7 +5,7 @@ version: 0.0.1 environment: sdk: '>=1.13.0 <2.0.0' dependencies: - angular2: 2.0.0-beta.14 + angular2: 2.0.0-beta.15 browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/hierarchical-dependency-injection/dart/pubspec.yaml b/public/docs/_examples/hierarchical-dependency-injection/dart/pubspec.yaml index 53e328a859..68c8e5b71a 100644 --- a/public/docs/_examples/hierarchical-dependency-injection/dart/pubspec.yaml +++ b/public/docs/_examples/hierarchical-dependency-injection/dart/pubspec.yaml @@ -5,7 +5,7 @@ version: 0.0.1 environment: sdk: '>=1.13.0 <2.0.0' dependencies: - angular2: 2.0.0-beta.14 + angular2: 2.0.0-beta.15 browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/lifecycle-hooks/dart/pubspec.yaml b/public/docs/_examples/lifecycle-hooks/dart/pubspec.yaml index 678eafc9db..f0cbce54da 100644 --- a/public/docs/_examples/lifecycle-hooks/dart/pubspec.yaml +++ b/public/docs/_examples/lifecycle-hooks/dart/pubspec.yaml @@ -5,7 +5,7 @@ version: 0.0.1 environment: sdk: '>=1.13.0 <2.0.0' dependencies: - angular2: 2.0.0-beta.14 + angular2: 2.0.0-beta.15 browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/pipes/dart/pubspec.yaml b/public/docs/_examples/pipes/dart/pubspec.yaml index d373ebb3e6..848c11cd1c 100644 --- a/public/docs/_examples/pipes/dart/pubspec.yaml +++ b/public/docs/_examples/pipes/dart/pubspec.yaml @@ -5,7 +5,7 @@ version: 0.0.1 environment: sdk: '>=1.13.0 <2.0.0' dependencies: - angular2: 2.0.0-beta.14 + angular2: 2.0.0-beta.15 browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/quickstart/dart/pubspec.yaml b/public/docs/_examples/quickstart/dart/pubspec.yaml index 003c49f87f..fba4eb990d 100644 --- a/public/docs/_examples/quickstart/dart/pubspec.yaml +++ b/public/docs/_examples/quickstart/dart/pubspec.yaml @@ -7,7 +7,7 @@ version: 0.0.1 environment: sdk: '>=1.13.0 <2.0.0' dependencies: - angular2: 2.0.0-beta.14 + angular2: 2.0.0-beta.15 browser: ^0.10.0 # #enddocregion no-rewriter dart_to_js_script_rewriter: ^1.0.1 diff --git a/public/docs/_examples/structural-directives/dart/pubspec.yaml b/public/docs/_examples/structural-directives/dart/pubspec.yaml index 0d0cc0da2e..e774e73f66 100644 --- a/public/docs/_examples/structural-directives/dart/pubspec.yaml +++ b/public/docs/_examples/structural-directives/dart/pubspec.yaml @@ -5,7 +5,7 @@ version: 0.0.1 environment: sdk: '>=1.13.0 <2.0.0' dependencies: - angular2: 2.0.0-beta.14 + angular2: 2.0.0-beta.15 browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/template-syntax/dart/pubspec.yaml b/public/docs/_examples/template-syntax/dart/pubspec.yaml index a7b946d419..43df9c5d0f 100644 --- a/public/docs/_examples/template-syntax/dart/pubspec.yaml +++ b/public/docs/_examples/template-syntax/dart/pubspec.yaml @@ -5,7 +5,7 @@ version: 0.0.1 environment: sdk: '>=1.13.0 <2.0.0' dependencies: - angular2: 2.0.0-beta.14 + angular2: 2.0.0-beta.15 browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/toh-1/dart/pubspec.yaml b/public/docs/_examples/toh-1/dart/pubspec.yaml index 50fb62d8d5..5380671689 100644 --- a/public/docs/_examples/toh-1/dart/pubspec.yaml +++ b/public/docs/_examples/toh-1/dart/pubspec.yaml @@ -4,7 +4,7 @@ version: 0.0.1 environment: sdk: '>=1.13.0 <2.0.0' dependencies: - angular2: 2.0.0-beta.14 + angular2: 2.0.0-beta.15 browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/toh-1/dart/web/main.dart b/public/docs/_examples/toh-1/dart/web/main.dart index d5b50195c1..81c22cd91d 100644 --- a/public/docs/_examples/toh-1/dart/web/main.dart +++ b/public/docs/_examples/toh-1/dart/web/main.dart @@ -1,9 +1,9 @@ // #docregion pt1 -import 'package:angular2/bootstrap.dart'; +import 'package:angular2/platform/browser.dart'; import 'package:angular2_tour_of_heroes/app_component.dart'; main() { bootstrap(AppComponent); } -// #enddocregion pt1 \ No newline at end of file +// #enddocregion pt1 diff --git a/public/docs/_examples/toh-2/dart/pubspec.yaml b/public/docs/_examples/toh-2/dart/pubspec.yaml index ddfafde27c..f4d1c8caa0 100644 --- a/public/docs/_examples/toh-2/dart/pubspec.yaml +++ b/public/docs/_examples/toh-2/dart/pubspec.yaml @@ -3,9 +3,9 @@ version: 0.0.1 environment: sdk: '>=1.13.0 <2.0.0' dependencies: - angular2: 2.0.0-beta.1 + angular2: 2.0.0-beta.15 browser: ^0.10.0 - dart_to_js_script_rewriter: ^0.1.0+4 + dart_to_js_script_rewriter: ^1.0.1 transformers: - angular2: platform_directives: diff --git a/public/docs/_examples/toh-2/dart/web/main.dart b/public/docs/_examples/toh-2/dart/web/main.dart index 685cba5fce..129bd9620b 100644 --- a/public/docs/_examples/toh-2/dart/web/main.dart +++ b/public/docs/_examples/toh-2/dart/web/main.dart @@ -1,9 +1,9 @@ // #docregion pt2 -import 'package:angular2/bootstrap.dart'; +import 'package:angular2/platform/browser.dart'; import 'package:angular2_tour_of_heroes/app_component.dart'; main() { bootstrap(AppComponent); } -// #enddocregion pt2 \ No newline at end of file +// #enddocregion pt2 diff --git a/public/docs/_examples/toh-3/dart/pubspec.yaml b/public/docs/_examples/toh-3/dart/pubspec.yaml index 3e27b96128..f4d1c8caa0 100644 --- a/public/docs/_examples/toh-3/dart/pubspec.yaml +++ b/public/docs/_examples/toh-3/dart/pubspec.yaml @@ -3,7 +3,7 @@ version: 0.0.1 environment: sdk: '>=1.13.0 <2.0.0' dependencies: - angular2: 2.0.0-beta.14 + angular2: 2.0.0-beta.15 browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/_examples/toh-3/dart/web/main.dart b/public/docs/_examples/toh-3/dart/web/main.dart index d5b50195c1..81c22cd91d 100644 --- a/public/docs/_examples/toh-3/dart/web/main.dart +++ b/public/docs/_examples/toh-3/dart/web/main.dart @@ -1,9 +1,9 @@ // #docregion pt1 -import 'package:angular2/bootstrap.dart'; +import 'package:angular2/platform/browser.dart'; import 'package:angular2_tour_of_heroes/app_component.dart'; main() { bootstrap(AppComponent); } -// #enddocregion pt1 \ No newline at end of file +// #enddocregion pt1 diff --git a/public/docs/_examples/toh-4/dart/lib/app_component.dart b/public/docs/_examples/toh-4/dart/lib/app_component.dart new file mode 100644 index 0000000000..745d183d11 --- /dev/null +++ b/public/docs/_examples/toh-4/dart/lib/app_component.dart @@ -0,0 +1,106 @@ +// #docplaster +// #docregion +import 'dart:async'; + +import 'package:angular2/core.dart'; + +import 'hero.dart'; +import 'hero_detail_component.dart'; +// #docregion hero-service-import +import 'hero_service.dart'; + +// #enddocregion hero-service-import + +@Component( + selector: 'my-app', + template: ''' +

{{title}}

+

My Heroes

+ + + ''', + styles: const [ + ''' + .selected { + background-color: #CFD8DC !important; + color: white; + } + .heroes { + margin: 0 0 2em 0; + list-style-type: none; + padding: 0; + width: 10em; + } + .heroes li { + cursor: pointer; + position: relative; + left: 0; + background-color: #EEE; + margin: .5em; + padding: .3em 0em; + height: 1.6em; + border-radius: 4px; + } + .heroes li.selected:hover { + color: white; + } + .heroes li:hover { + color: #607D8B; + background-color: #EEE; + left: .1em; + } + .heroes .text { + position: relative; + top: -3px; + } + .heroes .badge { + display: inline-block; + font-size: small; + color: white; + padding: 0.8em 0.7em 0em 0.7em; + background-color: #607D8B; + line-height: 1em; + position: relative; + left: -1px; + top: -4px; + height: 1.8em; + margin-right: .8em; + border-radius: 4px 0px 0px 4px; + } + ''' + ], + directives: const [ + HeroDetailComponent + ], + providers: const [ + HeroService + ]) +class AppComponent implements OnInit { + String title = 'Tour of Heroes'; + List heroes; + Hero selectedHero; + + final HeroService _heroService; + + AppComponent(this._heroService); + +// #docregion get-heroes + getHeroes() async { + heroes = await _heroService.getHeroes(); + } +// #enddocregion get-heroes + + ngOnInit() { + getHeroes(); + } + + onSelect(Hero hero) { + selectedHero = hero; + } +} diff --git a/public/docs/_examples/toh-4/dart/lib/app_component_1.dart b/public/docs/_examples/toh-4/dart/lib/app_component_1.dart new file mode 100644 index 0000000000..2f2cbb0dd0 --- /dev/null +++ b/public/docs/_examples/toh-4/dart/lib/app_component_1.dart @@ -0,0 +1,64 @@ +// #docplaster +// #docregion on-init +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( + selector: 'my-app', + template: ''' +
+ {{hero.name}} +
+ + ''', + directives: const [HeroDetailComponent], + // #docregion providers + providers: const [HeroService]) +// #enddocregion providers +// #docregion on-init +class AppComponent implements OnInit { + // #enddocregion on-init + String title = 'Tour of Heroes'; + // #docregion heroes-prop + List heroes; + // #enddocregion heroes-prop + Hero selectedHero; + + // #docregion new-service + HeroService heroService = new HeroService(); // don't do this + // #enddocregion new-service + // #docregion ctor + final HeroService _heroService; + AppComponent(this._heroService); + // #enddocregion ctor + // #docregion getHeroes + getHeroes() { + //#docregion get-heroes + heroes = _heroService.getHeroes(); + // #enddocregion get-heroes + } + // #enddocregion getHeroes + + // #docregion ng-on-init + // #docregion on-init + ngOnInit() { + // #enddocregion on-init + getHeroes(); + // #docregion on-init + } + // #enddocregion on-init + // #enddocregion ng-on-init + + onSelect(Hero hero) { + selectedHero = hero; + } + // #docregion on-init +} +// #enddocregion on-init diff --git a/public/docs/_examples/toh-4/dart/lib/hero.dart b/public/docs/_examples/toh-4/dart/lib/hero.dart new file mode 100644 index 0000000000..828f8cebab --- /dev/null +++ b/public/docs/_examples/toh-4/dart/lib/hero.dart @@ -0,0 +1,6 @@ +class Hero { + final int id; + String name; + + Hero(this.id, this.name); +} diff --git a/public/docs/_examples/toh-4/dart/lib/hero_detail_component.dart b/public/docs/_examples/toh-4/dart/lib/hero_detail_component.dart new file mode 100644 index 0000000000..14a1382348 --- /dev/null +++ b/public/docs/_examples/toh-4/dart/lib/hero_detail_component.dart @@ -0,0 +1,20 @@ +import 'package:angular2/core.dart'; + +import 'hero.dart'; + +@Component( + selector: 'my-hero-detail', + template: ''' +
+

{{hero.name}} details!

+
{{hero.id}}
+
+ + +
+
+ ''', + inputs: const ['hero']) +class HeroDetailComponent { + Hero hero; +} diff --git a/public/docs/_examples/toh-4/dart/lib/hero_service.dart b/public/docs/_examples/toh-4/dart/lib/hero_service.dart new file mode 100644 index 0000000000..4fa0b97e1c --- /dev/null +++ b/public/docs/_examples/toh-4/dart/lib/hero_service.dart @@ -0,0 +1,23 @@ +// #docplaster +// #docregion +import 'dart:async'; + +import 'package:angular2/core.dart'; + +import 'hero.dart'; +import 'mock_heroes.dart'; + +@Injectable() +class HeroService { + //#docregion get-heroes + Future> getHeroes() async => mockHeroes; + //#enddocregion get-heroes + + // See the "Take it slow" appendix + //#docregion get-heroes-slowly + Future> getHeroesSlowly() { + return new Future.delayed(const Duration(seconds: 2), () => mockHeroes); + } + //#enddocregion get-heroes-slowly +} +// #enddocregion diff --git a/public/docs/_examples/toh-4/dart/lib/hero_service_1.dart b/public/docs/_examples/toh-4/dart/lib/hero_service_1.dart new file mode 100644 index 0000000000..c95aeea7f8 --- /dev/null +++ b/public/docs/_examples/toh-4/dart/lib/hero_service_1.dart @@ -0,0 +1,28 @@ +// #docplaster +// #docregion final +// #docregion empty-class +import 'package:angular2/core.dart'; + +// #enddocregion empty-class +import 'hero.dart'; +import 'mock_heroes.dart'; + +// #docregion getHeroes-stub +@Injectable() +class HeroService { +// #enddocregion getHeroes-stub +// #enddocregion empty-class +// #enddocregion final + /* +// #docregion getHeroes-stub + List getHeroes() {} +// #enddocregion getHeroes-stub + */ +// #docregion final + List getHeroes() => mockHeroes; +// #docregion empty-class +// #docregion getHeroes-stub +} +// #enddocregion getHeroes-stub +// #enddocregion empty-class +// #enddocregion final diff --git a/public/docs/_examples/toh-4/dart/lib/mock_heroes.dart b/public/docs/_examples/toh-4/dart/lib/mock_heroes.dart new file mode 100644 index 0000000000..55434761a2 --- /dev/null +++ b/public/docs/_examples/toh-4/dart/lib/mock_heroes.dart @@ -0,0 +1,16 @@ +// #docregion +import 'hero.dart'; + +final List mockHeroes = [ + new Hero(11, "Mr. Nice"), + new Hero(12, "Narco"), + new Hero(13, "Bombasto"), + new Hero(14, "Celeritas"), + new Hero(15, "Magneta"), + new Hero(16, "RubberMan"), + new Hero(17, "Dynama"), + new Hero(18, "Dr IQ"), + new Hero(19, "Magma"), + new Hero(20, "Tornado") +]; +// #enddocregion \ No newline at end of file diff --git a/public/docs/_examples/toh-4/dart/pubspec.yaml b/public/docs/_examples/toh-4/dart/pubspec.yaml new file mode 100644 index 0000000000..f4d1c8caa0 --- /dev/null +++ b/public/docs/_examples/toh-4/dart/pubspec.yaml @@ -0,0 +1,15 @@ +name: angular2_tour_of_heroes +version: 0.0.1 +environment: + sdk: '>=1.13.0 <2.0.0' +dependencies: + angular2: 2.0.0-beta.15 + browser: ^0.10.0 + 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 + entry_points: web/main.dart diff --git a/public/docs/_examples/toh-4/dart/web/index.html b/public/docs/_examples/toh-4/dart/web/index.html new file mode 100644 index 0000000000..059daeed4c --- /dev/null +++ b/public/docs/_examples/toh-4/dart/web/index.html @@ -0,0 +1,10 @@ + + + + + + + + Loading... + + diff --git a/public/docs/_examples/toh-4/dart/web/main.dart b/public/docs/_examples/toh-4/dart/web/main.dart new file mode 100644 index 0000000000..81c22cd91d --- /dev/null +++ b/public/docs/_examples/toh-4/dart/web/main.dart @@ -0,0 +1,9 @@ +// #docregion pt1 +import 'package:angular2/platform/browser.dart'; + +import 'package:angular2_tour_of_heroes/app_component.dart'; + +main() { + bootstrap(AppComponent); +} +// #enddocregion pt1 diff --git a/public/docs/_examples/toh-4/dart/web/main_1.dart b/public/docs/_examples/toh-4/dart/web/main_1.dart new file mode 100644 index 0000000000..7d3d59c77d --- /dev/null +++ b/public/docs/_examples/toh-4/dart/web/main_1.dart @@ -0,0 +1,9 @@ +// #docregion pt1 +import 'package:angular2/platform/browser.dart'; + +import 'package:angular2_tour_of_heroes/app_component_1.dart'; + +main() { + bootstrap(AppComponent); +} +// #enddocregion pt1 diff --git a/public/docs/_examples/toh-5/dart/pubspec.yaml b/public/docs/_examples/toh-5/dart/pubspec.yaml index 2f88d9250e..699cb6bdae 100644 --- a/public/docs/_examples/toh-5/dart/pubspec.yaml +++ b/public/docs/_examples/toh-5/dart/pubspec.yaml @@ -5,12 +5,14 @@ version: 0.0.1 environment: sdk: '>=1.13.0 <2.0.0' dependencies: - angular2: 2.0.0-beta.14 + angular2: 2.0.0-beta.15 browser: ^0.10.0 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 diff --git a/public/docs/_examples/toh-5/dart/web/index.html b/public/docs/_examples/toh-5/dart/web/index.html index db501e102e..0d2d000077 100644 --- a/public/docs/_examples/toh-5/dart/web/index.html +++ b/public/docs/_examples/toh-5/dart/web/index.html @@ -3,8 +3,8 @@ - - + + Angular 2 Tour of Heroes diff --git a/public/docs/_examples/user-input/dart/pubspec.yaml b/public/docs/_examples/user-input/dart/pubspec.yaml index 5704281d09..c069b15ffa 100644 --- a/public/docs/_examples/user-input/dart/pubspec.yaml +++ b/public/docs/_examples/user-input/dart/pubspec.yaml @@ -5,7 +5,7 @@ version: 0.0.1 environment: sdk: '>=1.13.0 <2.0.0' dependencies: - angular2: 2.0.0-beta.14 + angular2: 2.0.0-beta.15 browser: ^0.10.0 dart_to_js_script_rewriter: ^1.0.1 transformers: diff --git a/public/docs/dart/latest/quickstart.jade b/public/docs/dart/latest/quickstart.jade index abbf191bc5..3d17db49c6 100644 --- a/public/docs/dart/latest/quickstart.jade +++ b/public/docs/dart/latest/quickstart.jade @@ -41,7 +41,7 @@ p. specify the angular2 and browser packages as dependencies, as well as the angular2 transformer. Angular 2 is still changing, so provide an exact version: - 2.0.0-beta.14. + 2.0.0-beta.15. +makeExample('quickstart/dart/pubspec.yaml', 'no-rewriter', 'pubspec.yaml') diff --git a/public/docs/dart/latest/tutorial/toh-pt4.jade b/public/docs/dart/latest/tutorial/toh-pt4.jade index 7c488613dd..238f23e06f 100644 --- a/public/docs/dart/latest/tutorial/toh-pt4.jade +++ b/public/docs/dart/latest/tutorial/toh-pt4.jade @@ -1,14 +1,399 @@ include ../_util-fns :marked - We're working on the Dart version of this case study. - In the meantime, please see these resources: + # Services + The Tour of Heroes is evolving and we anticipate adding more components in the near future. - * [Services](/docs/ts/latest/tutorial/toh-pt4.html): - The TypeScript version of this chapter + Multiple components will need access to hero data and we don't want to copy and + paste the same code over and over. + Instead, we'll create a single reusable data service and learn to + inject it in the components that need it. - * [Dart source code](https://github.com/angular/angular.io/tree/master/public/docs/_examples/toh-5/dart): - A preliminary Dart version of the Tour of Heroes app, - featuring the hero editor, a master/detail page, - multiple components, services, and routing + Refactoring data access to a separate service keeps the component lean and focused on supporting the view. + 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. + + The complete source code for the example app in this chapter is + [in GitHub](https://github.com/angular/angular.io/tree/master/public/docs/_examples/toh-4/dart). + +.l-main-section +:marked + ## Where We Left Off + Before we continue with our Tour of Heroes, let’s verify we have the following structure. + If not, we’ll need to go back and follow the previous chapters. + +.filetree + .file angular2_tour_of_heroes + .children + .file lib + .children + .file app_component.dart + .file hero.dart + .file hero_detail_component.dart + .file web + .children + .file index.html + .file main.dart + .file pubspec.yaml +:marked + ### Keep the app compiling and running + Open a terminal/console window. + Start the Dart compiler, watch for changes, and start our server by entering the command: + +code-example(format="." language="bash"). + pub serve + +:marked + The application runs and updates automatically as we continue to build the Tour of Heroes. + + ## Creating a Hero Service + Our stakeholders have shared their larger vision for our app. + They tell us they want to show the heroes in various ways on different pages. + We already can select a hero from a list. + Soon we'll add a dashboard with the top performing heroes and create a separate view for editing hero details. + All three views need hero data. + + At the moment the `AppComponent` defines mock heroes for display. + We have at least two objections. + 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 + share that service with all components that need heroes. + + ### Create the HeroService + Create a file in the `lib` folder called `hero_service.dart`. +.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"). + 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=".") + +:marked + ### Injectable Services + Notice that we used an `@Injectable()` annotation. +.callout.is-helpful + :marked + **Don't forget the parentheses!** Neglecting them leads to an error that's difficult to diagnose. +:marked + Dart sees the `@Injectable()` annotation and emits metadata about our service, + metadata that Angular may need to inject other dependencies into this service. + + The `HeroService` doesn't have any dependencies *at the moment*. Add the annotation anyway. + It is a "best practice" to apply the `@Injectable()` annotation ​*from the start*​ + both for consistency and for future-proofing. + +: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=".") +:marked + We're holding back on the implementation for a moment to make an important point. + + The consumer of our service doesn't know how the service gets the data. + Our `HeroService` could get `Hero` data from anywhere. + It could get the data from a web service or local storage + or from a mock data source. + + That's the beauty of removing data access from the component. + We can change our minds about the implementation as often as we like, + for whatever reason, without touching any of the components that need heroes. + + + ### Mock Heroes + 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`. + 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)') +: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=".") +: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=".") +: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=".") +: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: ++makeExample('toh-4/dart/lib/app_component_1.dart', 'new-service')(format=".") +:marked + That's a bad idea for several reasons including + + * Our component has to know how to create a `HeroService`. + If we ever change the `HeroService` constructor, + 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". + What if the service should cache heroes and share that cache with others? + We couldn't do that. + + * We're locking the `AppComponent` into a specific implementation of the `HeroService`. + It will be hard to switch implementations for different scenarios. + Can we operate offline? + Will we need different mocked versions under test? + Not easy. + + *What if ... what if ... Hey, we've got work to do!* + + We get it. Really we do. + But it is so ridiculously easy to avoid these problems that there is no excuse for doing it wrong. + + ### Inject the *HeroService* + + Three lines replace the one line of *new*: + 1. We add a property. + 1. We add a constructor that sets the property. + 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='.') +:marked + The constructor does nothing except set the `_heroService` + property. The `HeroService` type of `_heroService` + identifies the constructor's parameter as + a `HeroService` injection site. + + Now Angular will know to supply an instance of the `HeroService` when it creates a new `AppComponent`. + + Angular has to get that instance from somewhere. That's the role of the Angular *Dependency Injector*. + The **Injector** has a **container** of previously created services. + Either it finds and returns a pre-existing `HeroService` from its container or it creates a new instance, adds + it to the container, and returns it to Angular. + +.l-sub-section + :marked + Learn more about Dependency Injection in the [Dependency Injection](../guide/dependency-injection.html) chapter. +: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"). + 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=".") +: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. + +.l-sub-section + :marked + ### Services and the component tree + + Recall that the `AppComponent` creates an instance of `HeroDetail` by virtue of the + `` tag at the bottom of its template. That `HeroDetail` is a child of the `AppComponent`. + + 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=".") + :marked + The `HeroDetailComponent` must *not* repeat its parent's `providers` list! Guess [why](#shadow-provider). + + The `AppComponent` is the top level component of our application. + There should be only one instance of that component and only one instance of the `HeroService` in our entire app. +:marked + ### *getHeroes* in the *AppComponent* + We've got the service in a `_heroService` private variable. Let's use it. + + We pause to think. We can call the service and get the data in one line. ++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=".") + + +:marked + ### The *ngOnInit* Lifecycle Hook + `AppComponent` should fetch and display heroes without a fuss. + Where do we call the `getHeroes` method? In a constructor? We do *not*! + + Years of experience and bitter tears have taught us to keep complex logic out of the constructor, + especially anything that might call a server as a data access method is sure to do. + + The constructor is for simple initializations like wiring constructor parameters to properties. + It's not for heavy lifting. We should be able to create a component in a test and not worry that it + might do real work — like calling a server! — before we tell it to do so. + + If not the constructor, something has to call `getHeroes`. + + Angular will call it if we implement the Angular **ngOnInit** *Lifecycle Hook*. + Angular offers a number of interfaces for tapping into critical moments in the component lifecycle: + at creation, after each change, and at its eventual destruction. + + Each interface has a single method. When the component implements that method, Angular calls it at the appropriate time. +.l-sub-section + :marked + 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=".") +: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=".") +: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 + 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=".") +:marked + Ask for heroes and they are there in the returned result. + + Someday we're going to get heroes from a remote server. We don’t call http yet, but we aspire to in later chapters. + + When we do, we'll have to wait for the server to respond and we won't be able to block the UI while we wait, + even if we want to (which we shouldn't) because the browser won't block. + + We'll have to use some kind of asynchronous technique and that will change the signature of our `getHeroes` method. + + We'll use *futures*. + + ### The Hero Service returns a future + + 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. +.l-sub-section + :marked + We are simplifying. Learn about Futures 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=".") +: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. + +.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. + 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 + 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=".") +:marked + As a result of our change to `HeroService`, we're now setting `heroes` to a future 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=".") +:marked + Our code waits until the future 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 + responding to a name selection with a detail view. +.l-sub-section + :marked + Check out the "[Take it slow](#slow)" appendix to see what the app might be like with a poor connection. +:marked + ### Review the App Structure + Let’s verify that we have the following structure after all of our good refactoring in this chapter: + +.filetree + .file angular2_tour_of_heroes + .children + .file lib + .children + .file app_component.dart + .file hero.dart + .file hero_detail_component.dart + .file hero_service.dart + .file mock_heroes.dart + .file web + .children + .file index.html + .file main.dart + .file pubspec.yaml +:marked + Here are the code files we discussed in this chapter. + ++makeTabs(` + toh-4/dart/lib/hero_service.dart, + toh-4/dart/lib/app_component.dart, + toh-4/dart/lib/mock_heroes.dart + `,'',` + lib/hero_service.dart, + lib/app_component.dart, + lib/mock_heroes.dart + `) +:marked + ## The Road We’ve Travelled + Let’s take stock of what we’ve 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 + + + ### The Road Ahead + Our Tour of Heroes has become more reusable using shared components and services. + We want to create a dashboard, add menu links that route between the views, and format data in a template. + As our app evolves, we’ll learn how to design it to make it easier to grow and maintain. + + We learn about Angular Component Router and navigation among the views in the [next tutorial](toh-pt5.html) chapter. + +.l-main-section + +:marked + ### Appendix: Take it slow + + 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=".") +:marked + Like `getHeroes`, it also returns a future. + But this future waits 2 seconds before resolving the future with mock heroes. + + Back in the `AppComponent`, replace + `_heroService.getHeroes` with `_heroService.getHeroesSlowly` + and see how the app behaves. + +.l-main-section + +:marked + ### Appendix: Shadowing the parent's service + + We stated [earlier](#child-component) that if we injected the parent `AppComponent` `HeroService` + into the `HeroDetailComponent`, *we must not add a providers list* to the `HeroDetailComponent` metadata. + + Why? Because that tells Angular to create a new instance of the `HeroService` at the `HeroDetailComponent` level. + The `HeroDetailComponent` doesn't want its *own* service instance; it wants its *parent's* service instance. + Adding the `providers` list creates a new service instance that shadows the parent instance. + + Think carefully about where and when to register a provider. + Understand the scope of that registration. Be careful not to create a new service instance at the wrong level.