docs(toh-6/dart): first edition of prose and example code (#1687)
* docs(toh-6/dart): first edition of prose and example code NOTE: this PR depends on #1686. Dart prose and example match TS except that: - No child-to-parent event emission occurs. - Support for Add Hero is added as an unconditional feature of the Heroes view. - http `_post` takes only a name - http `delete` takes only a hero id. - The Dart in-memory-data-service has been dropped in favor of an implementation based on the "standard" `http.testing.MockClient` class. * post-review changes
This commit is contained in:
		
							parent
							
								
									97fbda0d76
								
							
						
					
					
						commit
						f06398cd89
					
				
							
								
								
									
										5
									
								
								public/docs/_examples/toh-6/dart/.docsync.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								public/docs/_examples/toh-6/dart/.docsync.json
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| { | ||||
|   "title": "Tour of Heroes: HTTP", | ||||
|   "docPart": "tutorial", | ||||
|   "docHref": "toh-pt6.html" | ||||
| } | ||||
							
								
								
									
										29
									
								
								public/docs/_examples/toh-6/dart/lib/app_component.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								public/docs/_examples/toh-6/dart/lib/app_component.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| /* #docregion */ | ||||
| h1 { | ||||
|   font-size: 1.2em; | ||||
|   color: #999; | ||||
|   margin-bottom: 0; | ||||
| } | ||||
| h2 { | ||||
|   font-size: 2em; | ||||
|   margin-top: 0; | ||||
|   padding-top: 0; | ||||
| } | ||||
| nav a { | ||||
|   padding: 5px 10px; | ||||
|   text-decoration: none; | ||||
|   margin-top: 10px; | ||||
|   display: inline-block; | ||||
|   background-color: #eee; | ||||
|   border-radius: 4px; | ||||
| } | ||||
| nav a:visited, a:link { | ||||
|   color: #607D8B; | ||||
| } | ||||
| nav a:hover { | ||||
|   color: #039be5; | ||||
|   background-color: #CFD8DC; | ||||
| } | ||||
| nav a.router-link-active { | ||||
|   color: #039be5; | ||||
| } | ||||
							
								
								
									
										45
									
								
								public/docs/_examples/toh-6/dart/lib/app_component.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								public/docs/_examples/toh-6/dart/lib/app_component.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | ||||
| // #docplaster | ||||
| // #docregion | ||||
| import 'package:angular2/core.dart'; | ||||
| import 'package:angular2/router.dart'; | ||||
| 
 | ||||
| import 'package:angular2_tour_of_heroes/heroes_component.dart'; | ||||
| import 'package:angular2_tour_of_heroes/hero_service.dart'; | ||||
| import 'package:angular2_tour_of_heroes/dashboard_component.dart'; | ||||
| // #docregion hero-detail-import | ||||
| import 'package:angular2_tour_of_heroes/hero_detail_component.dart'; | ||||
| // #enddocregion hero-detail-import | ||||
| 
 | ||||
| @Component( | ||||
|     selector: 'my-app', | ||||
|     // #docregion template | ||||
|     template: ''' | ||||
|       <h1>{{title}}</h1> | ||||
|       <nav> | ||||
|         <a [routerLink]="['Dashboard']">Dashboard</a> | ||||
|         <a [routerLink]="['Heroes']">Heroes</a> | ||||
|       </nav> | ||||
|       <router-outlet></router-outlet>''', | ||||
|     // #enddocregion template | ||||
|     // #docregion style-urls | ||||
|     styleUrls: const ['app_component.css'], | ||||
|     // #enddocregion style-urls | ||||
|     directives: const [ROUTER_DIRECTIVES], | ||||
|     providers: const [HeroService, ROUTER_PROVIDERS]) | ||||
| @RouteConfig(const [ | ||||
|   // #docregion dashboard-route | ||||
|   const Route( | ||||
|       path: '/dashboard', | ||||
|       name: 'Dashboard', | ||||
|       component: DashboardComponent, | ||||
|       useAsDefault: true), | ||||
|   // #enddocregion dashboard-route | ||||
|   // #docregion hero-detail-route | ||||
|   const Route( | ||||
|       path: '/detail/:id', name: 'HeroDetail', component: HeroDetailComponent), | ||||
|   // #enddocregion hero-detail-route | ||||
|   const Route(path: '/heroes', name: 'Heroes', component: HeroesComponent) | ||||
| ]) | ||||
| class AppComponent { | ||||
|   String title = 'Tour of Heroes'; | ||||
| } | ||||
							
								
								
									
										61
									
								
								public/docs/_examples/toh-6/dart/lib/dashboard_component.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								public/docs/_examples/toh-6/dart/lib/dashboard_component.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,61 @@ | ||||
| /* #docregion */ | ||||
| [class*='col-'] { | ||||
|   float: left; | ||||
| } | ||||
| *, *:after, *:before { | ||||
| 	-webkit-box-sizing: border-box; | ||||
| 	-moz-box-sizing: border-box; | ||||
| 	box-sizing: border-box; | ||||
| } | ||||
| h3 { | ||||
|   text-align: center; margin-bottom: 0; | ||||
| } | ||||
| [class*='col-'] { | ||||
|   padding-right: 20px; | ||||
|   padding-bottom: 20px; | ||||
| } | ||||
| [class*='col-']:last-of-type { | ||||
|   padding-right: 0; | ||||
| } | ||||
| .grid { | ||||
|   margin: 0; | ||||
| } | ||||
| .col-1-4 { | ||||
|   width: 25%; | ||||
| } | ||||
| .module { | ||||
| 	padding: 20px; | ||||
| 	text-align: center; | ||||
| 	color: #eee; | ||||
| 	max-height: 120px; | ||||
| 	min-width: 120px; | ||||
| 	background-color: #607D8B; | ||||
| 	border-radius: 2px; | ||||
| } | ||||
| h4 { | ||||
|   position: relative; | ||||
| } | ||||
| .module:hover { | ||||
|   background-color: #EEE; | ||||
|   cursor: pointer; | ||||
|   color: #607d8b; | ||||
| } | ||||
| .grid-pad { | ||||
|   padding: 10px 0; | ||||
| } | ||||
| .grid-pad > [class*='col-']:last-of-type { | ||||
|   padding-right: 20px; | ||||
| } | ||||
| @media (max-width: 600px) { | ||||
| 	.module { | ||||
| 	  font-size: 10px; | ||||
| 	  max-height: 75px; } | ||||
| } | ||||
| @media (max-width: 1024px) { | ||||
| 	.grid { | ||||
| 	  margin: 0; | ||||
| 	} | ||||
| 	.module { | ||||
| 	  min-width: 60px; | ||||
| 	} | ||||
| } | ||||
| @ -0,0 +1,47 @@ | ||||
| // #docplaster | ||||
| // #docregion | ||||
| import 'dart:async'; | ||||
| 
 | ||||
| import 'package:angular2/core.dart'; | ||||
| // #docregion import-router | ||||
| import 'package:angular2/router.dart'; | ||||
| // #enddocregion import-router | ||||
| 
 | ||||
| import 'hero.dart'; | ||||
| import 'hero_service.dart'; | ||||
| 
 | ||||
| @Component( | ||||
|     selector: 'my-dashboard', | ||||
|     // #docregion template-url | ||||
|     templateUrl: 'dashboard_component.html', | ||||
|     // #enddocregion template-url | ||||
|     // #docregion css | ||||
|     styleUrls: const ['dashboard_component.css'] | ||||
|     // #enddocregion css | ||||
|     ) | ||||
| // #docregion component | ||||
| class DashboardComponent implements OnInit { | ||||
|   List<Hero> heroes; | ||||
| 
 | ||||
|   // #docregion ctor | ||||
|   final Router _router; | ||||
|   final HeroService _heroService; | ||||
| 
 | ||||
|   DashboardComponent(this._heroService, this._router); | ||||
| 
 | ||||
|   // #enddocregion ctor | ||||
| 
 | ||||
|   Future<Null> ngOnInit() async { | ||||
|     heroes = (await _heroService.getHeroes()).skip(1).take(4).toList(); | ||||
|   } | ||||
| 
 | ||||
|   // #docregion goto-detail | ||||
|   void gotoDetail(Hero hero) { | ||||
|     var link = [ | ||||
|       'HeroDetail', | ||||
|       {'id': hero.id.toString()} | ||||
|     ]; | ||||
|     _router.navigate(link); | ||||
|   } | ||||
| // #enddocregion goto-detail | ||||
| } | ||||
| @ -0,0 +1,11 @@ | ||||
| <!-- #docregion --> | ||||
| <h3>Top Heroes</h3> | ||||
| <div class="grid grid-pad"> | ||||
|   <!-- #docregion click --> | ||||
|   <div *ngFor="let hero of heroes" (click)="gotoDetail(hero)" class="col-1-4" > | ||||
|     <!-- #enddocregion click --> | ||||
|     <div class="module hero"> | ||||
|       <h4>{{hero.name}}</h4> | ||||
|     </div> | ||||
|   </div> | ||||
| </div> | ||||
							
								
								
									
										14
									
								
								public/docs/_examples/toh-6/dart/lib/hero.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								public/docs/_examples/toh-6/dart/lib/hero.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | ||||
| // #docregion | ||||
| class Hero { | ||||
|   final int id; | ||||
|   String name; | ||||
| 
 | ||||
|   Hero(this.id, this.name); | ||||
| 
 | ||||
|   factory Hero.fromJson(Map<String, dynamic> hero) => | ||||
|     new Hero(_toInt(hero['id']), hero['name']); | ||||
| 
 | ||||
|   Map toJson() => {'id': id, 'name': name}; | ||||
| } | ||||
| 
 | ||||
| int _toInt(id) => id is int ? id : int.parse(id); | ||||
| @ -0,0 +1,30 @@ | ||||
| /* #docregion */ | ||||
| label { | ||||
|   display: inline-block; | ||||
|   width: 3em; | ||||
|   margin: .5em 0; | ||||
|   color: #607D8B; | ||||
|   font-weight: bold; | ||||
| } | ||||
| input { | ||||
|   height: 2em; | ||||
|   font-size: 1em; | ||||
|   padding-left: .4em; | ||||
| } | ||||
| button { | ||||
|   margin-top: 20px; | ||||
|   font-family: Arial; | ||||
|   background-color: #eee; | ||||
|   border: none; | ||||
|   padding: 5px 10px; | ||||
|   border-radius: 4px; | ||||
|   cursor: pointer; cursor: hand; | ||||
| } | ||||
| button:hover { | ||||
|   background-color: #cfd8dc; | ||||
| } | ||||
| button:disabled { | ||||
|   background-color: #eee; | ||||
|   color: #ccc;  | ||||
|   cursor: auto; | ||||
| } | ||||
| @ -0,0 +1,61 @@ | ||||
| // #docplaster | ||||
| // #docregion , v2 | ||||
| import 'dart:async'; | ||||
| import 'dart:html'; | ||||
| 
 | ||||
| // #docregion import-oninit | ||||
| import 'package:angular2/core.dart'; | ||||
| // #enddocregion import-oninit | ||||
| // #docregion import-route-params | ||||
| import 'package:angular2/router.dart'; | ||||
| // #enddocregion import-route-params | ||||
| 
 | ||||
| import 'hero.dart'; | ||||
| // #docregion import-hero-service | ||||
| import 'hero_service.dart'; | ||||
| // #enddocregion import-hero-service | ||||
| 
 | ||||
| // #docregion extract-template | ||||
| @Component( | ||||
|     selector: 'my-hero-detail', | ||||
|     // #docregion template-url | ||||
|     templateUrl: 'hero_detail_component.html', | ||||
|     // #enddocregion template-url, v2 | ||||
|     styleUrls: const ['hero_detail_component.css'] | ||||
|     // #docregion v2 | ||||
|     ) | ||||
| // #enddocregion extract-template | ||||
| // #docregion implement | ||||
| class HeroDetailComponent implements OnInit { | ||||
|   // #enddocregion implement | ||||
|   Hero hero; | ||||
|   // #docregion ctor | ||||
|   final HeroService _heroService; | ||||
|   final RouteParams _routeParams; | ||||
| 
 | ||||
|   HeroDetailComponent(this._heroService, this._routeParams); | ||||
|   // #enddocregion ctor | ||||
| 
 | ||||
|   // #docregion ng-oninit | ||||
|   Future<Null> ngOnInit() async { | ||||
|     // #docregion get-id | ||||
|     var idString = _routeParams.get('id'); | ||||
|     var id = int.parse(idString, onError: (_) => null); | ||||
|     // #enddocregion get-id | ||||
|     if (id != null) hero = await (_heroService.getHero(id)); | ||||
|   } | ||||
|   // #enddocregion ng-oninit | ||||
| 
 | ||||
|   // #docregion save | ||||
|   Future<Null> save() async { | ||||
|     await _heroService.save(hero); | ||||
|     goBack(); | ||||
|   } | ||||
|   // #enddocregion save | ||||
| 
 | ||||
|   // #docregion go-back | ||||
|   void goBack() { | ||||
|     window.history.back(); | ||||
|   } | ||||
|   // #enddocregion go-back | ||||
| } | ||||
| @ -0,0 +1,15 @@ | ||||
| <!-- #docplaster --> | ||||
| <!-- #docregion --> | ||||
| <div *ngIf="hero != null"> | ||||
|   <h2>{{hero.name}} details!</h2> | ||||
|   <div> | ||||
|     <label>id: </label>{{hero.id}}</div> | ||||
|   <div> | ||||
|     <label>name: </label> | ||||
|     <input [(ngModel)]="hero.name" placeholder="name" /> | ||||
|   </div> | ||||
|   <button (click)="goBack()">Back</button> | ||||
|   <!-- #docregion save --> | ||||
|   <button (click)="save()">Save</button> | ||||
|   <!-- #enddocregion save --> | ||||
| </div> | ||||
							
								
								
									
										91
									
								
								public/docs/_examples/toh-6/dart/lib/hero_service.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								public/docs/_examples/toh-6/dart/lib/hero_service.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,91 @@ | ||||
| // #docregion | ||||
| import 'dart:async'; | ||||
| import 'dart:convert'; | ||||
| 
 | ||||
| import 'package:angular2/core.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| 
 | ||||
| import 'hero.dart'; | ||||
| 
 | ||||
| @Injectable() | ||||
| class HeroService { | ||||
|   // #docregion post | ||||
|   static final _headers = {'Content-Type': 'application/json'}; | ||||
|   // #enddocregion post | ||||
|   // #docregion getHeroes | ||||
|   static const _heroesUrl = 'app/heroes'; // URL to web API | ||||
| 
 | ||||
|   final Client _http; | ||||
| 
 | ||||
|   HeroService(this._http); | ||||
| 
 | ||||
|   Future<List<Hero>> getHeroes() async { | ||||
|     try { | ||||
|       final response = await _http.get(_heroesUrl); | ||||
|       final heroes = _extractData(response) | ||||
|           .map((value) => new Hero.fromJson(value)) | ||||
|           .toList(); | ||||
|       return heroes; | ||||
|       // #docregion catch | ||||
|     } catch (e) { | ||||
|       throw _handleError(e); | ||||
|     } | ||||
|     // #enddocregion catch | ||||
|   } | ||||
| 
 | ||||
|   // #docregion extract-data | ||||
|   dynamic _extractData(Response resp) => JSON.decode(resp.body)['data']; | ||||
|   // #enddocregion extract-data, getHeroes | ||||
| 
 | ||||
|   Future<Hero> getHero(int id) async => | ||||
|       (await getHeroes()).firstWhere((hero) => hero.id == id); | ||||
| 
 | ||||
|   // #docregion save | ||||
|   Future<Hero> save(dynamic heroOrName) => | ||||
|       heroOrName is Hero ? _put(heroOrName) : _post(heroOrName); | ||||
|   // #enddocregion save | ||||
| 
 | ||||
|   // #docregion handleError | ||||
|   Exception _handleError(dynamic e) { | ||||
|     print(e); // for demo purposes only | ||||
|     return new Exception('Server error; cause: $e'); | ||||
|   } | ||||
|   // #enddocregion handleError | ||||
| 
 | ||||
|   // #docregion post | ||||
|   Future<Hero> _post(String name) async { | ||||
|     try { | ||||
|       final response = await _http.post(_heroesUrl, | ||||
|           headers: _headers, body: JSON.encode({'name': name})); | ||||
|       return new Hero.fromJson(_extractData(response)); | ||||
|     } catch (e) { | ||||
|       throw _handleError(e); | ||||
|     } | ||||
|   } | ||||
|   // #enddocregion post | ||||
| 
 | ||||
|   // #docregion put | ||||
|   Future<Hero> _put(Hero hero) async { | ||||
|     try { | ||||
|       var url = '$_heroesUrl/${hero.id}'; | ||||
|       final response = | ||||
|           await _http.put(url, headers: _headers, body: JSON.encode(hero)); | ||||
|       return new Hero.fromJson(_extractData(response)); | ||||
|     } catch (e) { | ||||
|       throw _handleError(e); | ||||
|     } | ||||
|   } | ||||
|   // #enddocregion put | ||||
| 
 | ||||
|   // #docregion delete | ||||
|   Future<Null> delete(int id) async { | ||||
|     try { | ||||
|       var url = '$_heroesUrl/$id'; | ||||
|       await _http.delete(url, headers: _headers); | ||||
|     } catch (e) { | ||||
|       throw _handleError(e); | ||||
|     } | ||||
|   } | ||||
|   // #enddocregion delete | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										59
									
								
								public/docs/_examples/toh-6/dart/lib/heroes_component.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								public/docs/_examples/toh-6/dart/lib/heroes_component.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | ||||
| .selected { | ||||
|   background-color: #CFD8DC !important; | ||||
|   color: white; | ||||
| } | ||||
| .heroes { | ||||
|   margin: 0 0 2em 0; | ||||
|   list-style-type: none; | ||||
|   padding: 0; | ||||
|   width: 15em; | ||||
| } | ||||
| .heroes li { | ||||
|   cursor: pointer; | ||||
|   position: relative; | ||||
|   left: 0; | ||||
|   background-color: #EEE; | ||||
|   margin: .5em; | ||||
|   padding: .3em 0; | ||||
|   height: 1.6em; | ||||
|   border-radius: 4px; | ||||
| } | ||||
| .heroes li:hover { | ||||
|   color: #607D8B; | ||||
|   background-color: #DDD; | ||||
|   left: .1em; | ||||
| } | ||||
| .heroes li.selected:hover { | ||||
|   background-color: #BBD8DC !important; | ||||
|   color: white; | ||||
| } | ||||
| .heroes .text { | ||||
|   position: relative; | ||||
|   top: -3px; | ||||
| } | ||||
| .heroes .badge { | ||||
|   display: inline-block; | ||||
|   font-size: small; | ||||
|   color: white; | ||||
|   padding: 0.8em 0.7em 0 0.7em; | ||||
|   background-color: #607D8B; | ||||
|   line-height: 1em; | ||||
|   position: relative; | ||||
|   left: -1px; | ||||
|   top: -4px; | ||||
|   height: 1.8em; | ||||
|   margin-right: .8em; | ||||
|   border-radius: 4px 0 0 4px; | ||||
| } | ||||
| button { | ||||
|   font-family: Arial; | ||||
|   background-color: #eee; | ||||
|   border: none; | ||||
|   padding: 5px 10px; | ||||
|   border-radius: 4px; | ||||
|   cursor: pointer; | ||||
|   cursor: hand; | ||||
| } | ||||
| button:hover { | ||||
|   background-color: #cfd8dc; | ||||
| } | ||||
							
								
								
									
										69
									
								
								public/docs/_examples/toh-6/dart/lib/heroes_component.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								public/docs/_examples/toh-6/dart/lib/heroes_component.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | ||||
| // #docplaster | ||||
| // #docregion | ||||
| import 'dart:async'; | ||||
| 
 | ||||
| import 'package:angular2/core.dart'; | ||||
| import 'package:angular2/router.dart'; | ||||
| 
 | ||||
| import 'hero.dart'; | ||||
| import 'hero_detail_component.dart'; | ||||
| import 'hero_service.dart'; | ||||
| 
 | ||||
| @Component( | ||||
|     selector: 'my-heroes', | ||||
|     templateUrl: 'heroes_component.html', | ||||
|     styleUrls: const ['heroes_component.css'], | ||||
|     directives: const [HeroDetailComponent]) | ||||
| class HeroesComponent implements OnInit { | ||||
|   final Router _router; | ||||
|   final HeroService _heroService; | ||||
|   List<Hero> heroes; | ||||
|   Hero selectedHero; | ||||
|   // #docregion error | ||||
|   String errorMessage; | ||||
|   // #enddocregion error | ||||
| 
 | ||||
|   HeroesComponent(this._heroService, this._router); | ||||
| 
 | ||||
|   // #docregion addHero | ||||
|   Future<Null> addHero(String name) async { | ||||
|     name = name.trim(); | ||||
|     if (name.isEmpty) return; | ||||
|     try { | ||||
|       heroes.add(await _heroService.save(name)); | ||||
|     } catch (e) { | ||||
|       errorMessage = e.toString(); | ||||
|     } | ||||
|   } | ||||
|   // #enddocregion addHero | ||||
| 
 | ||||
|   // #docregion deleteHero | ||||
|   Future<Null> deleteHero(int id, event) async { | ||||
|     try { | ||||
|       event.stopPropagation(); | ||||
|       await _heroService.delete(id); | ||||
|       heroes.removeWhere((hero) => hero.id == id); | ||||
|       if (selectedHero?.id == id) selectedHero = null; | ||||
|     } catch (e) { | ||||
|       errorMessage = e.toString(); | ||||
|     } | ||||
|   } | ||||
|   // #enddocregion deleteHero | ||||
| 
 | ||||
|   Future<Null> getHeroes() async { | ||||
|     heroes = await _heroService.getHeroes(); | ||||
|   } | ||||
| 
 | ||||
|   void ngOnInit() { | ||||
|     getHeroes(); | ||||
|   } | ||||
| 
 | ||||
|   void onSelect(Hero hero) { | ||||
|     selectedHero = hero; | ||||
|   } | ||||
| 
 | ||||
|   Future<Null> gotoDetail() => _router.navigate([ | ||||
|         'HeroDetail', | ||||
|         {'id': selectedHero.id.toString()} | ||||
|       ]); | ||||
| } | ||||
							
								
								
									
										31
									
								
								public/docs/_examples/toh-6/dart/lib/heroes_component.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								public/docs/_examples/toh-6/dart/lib/heroes_component.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| <!-- #docplaster --> | ||||
| <!-- #docregion --> | ||||
| <h2>My Heroes</h2> | ||||
| <!-- #docregion add-and-error --> | ||||
| <div class="error" *ngIf="errorMessage != null">{{errorMessage}}</div> | ||||
| <div> | ||||
|   Name: <input #newHeroName /> | ||||
|   <button (click)="addHero(newHeroName.value); newHeroName.value=''"> | ||||
|     Add New Hero | ||||
|   </button> | ||||
| </div> | ||||
| <!-- #enddocregion add-and-error --> | ||||
| <ul class="heroes"> | ||||
|   <li *ngFor="let hero of heroes" | ||||
|     [class.selected]="hero === selectedHero" | ||||
|     (click)="onSelect(hero)"> | ||||
|     <span class="badge">{{hero.id}}</span> {{hero.name}} | ||||
|     <!-- #docregion delete --> | ||||
|     <button class="delete-button" (click)="deleteHero(hero.id, $event)">x</button> | ||||
|     <!-- #enddocregion delete --> | ||||
|   </li> | ||||
| </ul> | ||||
| <!-- #docregion mini-detail --> | ||||
| <div *ngIf="selectedHero != null"> | ||||
|   <h2> | ||||
|     <!-- #docregion pipe --> | ||||
|     {{selectedHero.name | uppercase}} is my hero | ||||
|     <!-- #enddocregion pipe --> | ||||
|   </h2> | ||||
|   <button (click)="gotoDetail()">View Details</button> | ||||
| </div> | ||||
| @ -0,0 +1,64 @@ | ||||
| // #docregion | ||||
| import 'dart:async'; | ||||
| import 'dart:convert'; | ||||
| 
 | ||||
| // #docregion init | ||||
| import 'package:angular2/core.dart'; | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:http/testing.dart'; | ||||
| 
 | ||||
| import 'hero.dart'; | ||||
| 
 | ||||
| @Injectable() | ||||
| class InMemoryDataService extends MockClient { | ||||
|   static final _initialHeroes = [ | ||||
|     {'id': 11, 'name': 'Mr. Nice'}, | ||||
|     {'id': 12, 'name': 'Narco'}, | ||||
|     {'id': 13, 'name': 'Bombasto'}, | ||||
|     {'id': 14, 'name': 'Celeritas'}, | ||||
|     {'id': 15, 'name': 'Magneta'}, | ||||
|     {'id': 16, 'name': 'RubberMan'}, | ||||
|     {'id': 17, 'name': 'Dynama2'}, | ||||
|     {'id': 18, 'name': 'Dr IQ'}, | ||||
|     {'id': 19, 'name': 'Magma'}, | ||||
|     {'id': 20, 'name': 'Tornado'} | ||||
|   ]; | ||||
|   // #enddocregion init | ||||
| 
 | ||||
|   static final List<Hero> _heroesDb = | ||||
|       _initialHeroes.map((json) => new Hero.fromJson(json)).toList(); | ||||
|   static int _nextId = 21; | ||||
| 
 | ||||
|   static Future<Response> _handler(Request request) async { | ||||
|     var data; | ||||
|     switch (request.method) { | ||||
|       case 'GET': | ||||
|         data = _heroesDb; | ||||
|         break; | ||||
|       case 'POST': | ||||
|         var name = JSON.decode(request.body)['name']; | ||||
|         var newHero = new Hero(_nextId++, name); | ||||
|         _heroesDb.add(newHero); | ||||
|         data = newHero; | ||||
|         break; | ||||
|       case 'PUT': | ||||
|         var heroChanges = new Hero.fromJson(JSON.decode(request.body)); | ||||
|         var targetHero = _heroesDb.firstWhere((h) => h.id == heroChanges.id); | ||||
|         targetHero.name = heroChanges.name; | ||||
|         data = targetHero; | ||||
|         break; | ||||
|       case 'DELETE': | ||||
|         var id = int.parse(request.url.pathSegments.last); | ||||
|         _heroesDb.removeWhere((hero) => hero.id == id); | ||||
|         // No data, so leave it as null. | ||||
|         break; | ||||
|       default: | ||||
|         throw 'Unimplemented HTTP method ${request.method}'; | ||||
|     } | ||||
|     return new Response(JSON.encode({'data': data}), 200, | ||||
|         headers: {'content-type': 'application/json'}); | ||||
|   } | ||||
| 
 | ||||
|   InMemoryDataService() : super(_handler); | ||||
|   // #docregion init | ||||
| } | ||||
							
								
								
									
										28
									
								
								public/docs/_examples/toh-6/dart/pubspec.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								public/docs/_examples/toh-6/dart/pubspec.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| # #docregion , additions | ||||
| name: angular2_tour_of_heroes | ||||
|   # #enddocregion additions | ||||
| description: Tour of Heroes | ||||
| version: 0.0.1 | ||||
| environment: | ||||
|   sdk: '>=1.13.0 <2.0.0' | ||||
|   # #docregion additions | ||||
| dependencies: | ||||
|   angular2: 2.0.0-beta.17 | ||||
|   # #enddocregion additions | ||||
|   browser: ^0.10.0 | ||||
|   dart_to_js_script_rewriter: ^1.0.1 | ||||
|   # #docregion additions | ||||
|   http: ^0.11.0 | ||||
| transformers: | ||||
| - angular2: | ||||
|     # #enddocregion additions | ||||
|     platform_directives: | ||||
|     - 'package:angular2/common.dart#COMMON_DIRECTIVES' | ||||
|     platform_pipes: | ||||
|     - 'package:angular2/common.dart#COMMON_PIPES' | ||||
|     # #docregion additions | ||||
|     entry_points: web/main.dart | ||||
|     resolved_identifiers: | ||||
|         BrowserClient: 'package:http/browser_client.dart' | ||||
|         Client: 'package:http/http.dart' | ||||
| - dart_to_js_script_rewriter | ||||
							
								
								
									
										18
									
								
								public/docs/_examples/toh-6/dart/web/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								public/docs/_examples/toh-6/dart/web/index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| <!DOCTYPE html> | ||||
| <!-- #docregion --> | ||||
| <html> | ||||
|   <head> | ||||
|     <base href="/"> | ||||
|     <title>Angular 2 Tour of Heroes</title> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||
| 
 | ||||
|     <link rel="stylesheet" href="styles.css"> | ||||
|     <link rel="stylesheet" href="sample.css"> | ||||
| 
 | ||||
|     <script defer src="main.dart" type="application/dart"></script> | ||||
|     <script defer src="packages/browser/dart.js"></script> | ||||
|   </head> | ||||
|   <body> | ||||
|     <my-app>Loading...</my-app> | ||||
|   </body> | ||||
| </html> | ||||
							
								
								
									
										29
									
								
								public/docs/_examples/toh-6/dart/web/main.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								public/docs/_examples/toh-6/dart/web/main.dart
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| // #docplaster | ||||
| // #docregion final | ||||
| // #docregion v1 | ||||
| import 'package:angular2/core.dart'; | ||||
| import 'package:angular2/platform/browser.dart'; | ||||
| import 'package:angular2_tour_of_heroes/app_component.dart'; | ||||
| // #enddocregion v1 | ||||
| import 'package:http/http.dart'; | ||||
| import 'package:angular2_tour_of_heroes/in_memory_data_service.dart'; | ||||
| 
 | ||||
| void main() { | ||||
|   bootstrap(AppComponent, | ||||
|       const [const Provider(Client, useClass: InMemoryDataService)]); | ||||
| } | ||||
| // #enddocregion final | ||||
| /* | ||||
| // #docregion v1 | ||||
| import 'package:http/browser_client.dart'; | ||||
| 
 | ||||
| void main() { | ||||
|   bootstrap(AppComponent, [ | ||||
|     provide(BrowserClient, useFactory: () => new BrowserClient(), deps: []) | ||||
|   ]); | ||||
|   // Simplify bootstrap provider list to [BrowserClient] | ||||
|   // once there is a fix for: | ||||
|   // https://github.com/angular/angular/issues/9673 | ||||
| } | ||||
| // #enddocregion v1 | ||||
| */ | ||||
							
								
								
									
										7
									
								
								public/docs/_examples/toh-6/dart/web/sample.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								public/docs/_examples/toh-6/dart/web/sample.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| /* #docregion */ | ||||
| .error {color:red;} | ||||
| button.delete-button { | ||||
|   float:right; | ||||
|   background-color: gray !important; | ||||
|   color:white; | ||||
| } | ||||
| @ -1 +1,141 @@ | ||||
| != partial("../../../_includes/_ts-temp") | ||||
| extends ../../../ts/latest/tutorial/toh-pt6.jade | ||||
| 
 | ||||
| block includes | ||||
|   include ../_util-fns | ||||
|   - var _Http = 'BrowserClient'; | ||||
|   - var _Angular_Http = 'Dart <code>BrowserClient</code>' | ||||
|   - var _httpUrl = 'https://pub.dartlang.org/packages/http' | ||||
|   - var _Angular_http_library = 'Dart <a href="' + _httpUrl + '"><b>http</b></a> package' | ||||
|   - var _HTTP_PROVIDERS = 'BrowserClient' | ||||
|   - var _JSON_stringify = 'JSON.encode' | ||||
| 
 | ||||
| block start-server-and-watch | ||||
|   :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(language="bash"). | ||||
|       pub serve | ||||
|   | ||||
| block http-library | ||||
|   :marked | ||||
|     We'll be using the !{_Angular_http_library}'s  | ||||
|     `BrowserClient` class to communicate with a server. | ||||
| 
 | ||||
|     ### Pubspec updates | ||||
|      | ||||
|     We need to add a package dependency for the !{_Angular_http_library}. | ||||
| 
 | ||||
|     We also need to add a `resolved_identifiers` entry, to inform the [angular2 | ||||
|     transformer][ng2x] that we'll be using `BrowserClient`. (For an explanation of why | ||||
|     this extra configuration is needed, see the [HTTP client chapter][guide-http].) We'll | ||||
|     also need to use `Client` from http, so let's add that now as well. | ||||
| 
 | ||||
|     Update `pubspec.yaml` to look like this (additions are highlighted): | ||||
| 
 | ||||
|     [guide-http]: ../guide/server-communication.html#!#http-providers | ||||
|     [ng2x]: https://github.com/angular/angular/wiki/Angular-2-Dart-Transformer | ||||
| 
 | ||||
|   - var stylePattern = { pnk: /(http.*|resolved_identifiers:|Browser.*|Client.*)/gm }; | ||||
|   +makeExcerpt('pubspec.yaml', 'additions', null, stylePattern) | ||||
| 
 | ||||
| block http-providers | ||||
|   :marked | ||||
|     Before our app can use `#{_Http}`, we have to register it as a service provider. | ||||
| 
 | ||||
| block backend | ||||
|   :marked | ||||
|     We want to replace `BrowserClient`, the service that talks to the remote server, | ||||
|     with the in-memory web API service.  | ||||
|     Our in-memory web API service, shown below, is implemented using the | ||||
|     `http` library `MockClient` class. | ||||
|     All `http` client implementations share a common `Client` interface, so | ||||
|     we'll have our app use the `Client` type so that we can freely switch between | ||||
|     implementations. | ||||
| 
 | ||||
| block dont-be-distracted-by-backend-subst | ||||
|   //- N/A | ||||
| 
 | ||||
| block get-heroes-details | ||||
|   :marked | ||||
|     To get the list of heroes, we first make an asynchronous call to | ||||
|     `http.get()`. Then we use the `_extractData` helper method to decode the | ||||
|     response payload (`body`). | ||||
| 
 | ||||
| block hero-detail-comp-extra-imports-and-vars | ||||
|   //- N/A | ||||
| 
 | ||||
| block hero-detail-comp-updates | ||||
|   :marked | ||||
|     ### Edit in the *HeroDetailComponent* | ||||
| 
 | ||||
|     We already have `HeroDetailComponent` for viewing details about a specific hero.  | ||||
|     Supporting edit functionality is a natural extension of the detail view, | ||||
|     so we are able to reuse `HeroDetailComponent` with a few tweaks. | ||||
| 
 | ||||
| block hero-detail-comp-save-and-goback | ||||
|   //- N/A | ||||
| 
 | ||||
| block add-new-hero-via-detail-comp | ||||
|   //- N/A | ||||
| 
 | ||||
| block heroes-comp-directives | ||||
|   //- N/A | ||||
| 
 | ||||
| block heroes-comp-add | ||||
|   //- N/A | ||||
| 
 | ||||
| block review | ||||
|   //- Not showing animated gif due to differences between TS and Dart implementations. | ||||
| 
 | ||||
| block filetree | ||||
|   .filetree | ||||
|     .file angular2-tour-of-heroes | ||||
|     .children | ||||
|       .file lib | ||||
|       .children | ||||
|         .file app_component.dart | ||||
|         .file app_component.css | ||||
|         .file dashboard_component.css | ||||
|         .file dashboard_component.html | ||||
|         .file dashboard_component.dart | ||||
|         .file hero.dart | ||||
|         .file hero_detail_component.css | ||||
|         .file hero_detail_component.html | ||||
|         .file hero_detail_component.dart | ||||
|         .file hero_service.dart | ||||
|         .file heroes_component.css | ||||
|         .file heroes_component.html | ||||
|         .file heroes_component.dart | ||||
|         .file main.dart | ||||
|         .file in_memory_data_service.dart (new) | ||||
|       .file web | ||||
|       .children | ||||
|         .file main.dart | ||||
|         .file index.html | ||||
|         .file sample.css (new) | ||||
|         .file styles.css | ||||
|       .file pubspec.yaml | ||||
| 
 | ||||
| block file-summary | ||||
|   +makeTabs( | ||||
|     `toh-6/dart/lib/hero.dart, | ||||
|      toh-6/dart/lib/hero_detail_component.dart, | ||||
|      toh-6/dart/lib/hero_detail_component.html, | ||||
|      toh-6/dart/lib/hero_service.dart, | ||||
|      toh-6/dart/lib/heroes_component.dart, | ||||
|      toh-6/dart/web/index.html, | ||||
|      toh-6/dart/web/main.dart, | ||||
|      toh-6/dart/web/sample.css`, | ||||
|     `,,,,,,final,`, | ||||
|     `lib/hero.dart, | ||||
|      lib/hero_detail_component.dart, | ||||
|      lib/hero_detail_component.html, | ||||
|      lib/hero_service.dart, | ||||
|      lib/heroes_component.dart, | ||||
|      web/index.html, | ||||
|      web/main.dart, | ||||
|      web/sample.css`) | ||||
| 
 | ||||
|   +makeExample('pubspec.yaml') | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user