samples(template-syntax/dart): fix sample & make it comply with style guidelines

closes #879
This commit is contained in:
Thibault Sottiaux 2016-02-23 14:33:54 +00:00 committed by Kathy Walrath
parent f01dc81fa1
commit d9b55cb9ac
7 changed files with 169 additions and 121 deletions

View File

@ -1,3 +1,16 @@
# Supported lint rules and documentation: http://dart-lang.github.io/linter/lints/
linter:
rules:
- always_declare_return_types
- camel_case_types
- empty_constructor_bodies
- annotate_overrides
- avoid_init_to_null
- constant_identifier_names
- one_member_abstracts
- slash_for_doc_comments
- sort_constructors_first
- unnecessary_brace_in_string_interp
analyzer:
# strong-mode: true

View File

@ -8,7 +8,7 @@ import 'hero.dart';
import 'hero_detail_component.dart';
import 'my_click_directive.dart';
enum Color { Red, Green, Blue }
enum Color { red, green, blue }
@Component(
selector: 'my-app',
@ -19,7 +19,17 @@ enum Color { Red, Green, Blue }
MyClickDirective,
MyClickDirective2
])
class AppComponent {
class AppComponent implements OnInit, AfterViewInit {
@override
void ngOnInit() {
refreshHeroes();
}
@override
void ngAfterViewInit() {
_detectNgForTrackByEffects();
}
String heroName;
String help;
String actionName = 'Go for it';
@ -34,10 +44,19 @@ class AppComponent {
bool isSpecial = true;
bool isUnchanged = true;
bool isSelected = false;
Color color = Color.Red;
List<Hero> heroes = Hero.MockHeroes;
Hero selectedHero = Hero.MockHeroes[0];
Hero currentHero = Hero.MockHeroes[0];
Color color = Color.red;
List<Hero> heroes;
Hero currentHero;
// #docregion refresh-heroes
/// Updates [this.heroes] with fresh set of cloned heroes.
void refreshHeroes() {
heroes = mockHeroes.map((hero) => hero.clone()).toList();
currentHero = heroes[0];
}
// #enddocregion refresh-heroes
final Hero nullHero = null;
Map product = {'name': 'frimfram', 'price': 42};
FormElement form;
@ -54,33 +73,20 @@ class AppComponent {
// Public Domain terms of use http://www.clker.com/disclaimer.html
final String villainImageUrl = 'assets/images/villain.png';
// #docregion setClasses
Map classes = {
'saveable': false,
'modified': false,
'special': false
};
// #enddocregion setClasses
void alerter(String msg) {
window.alert(msg);
}
// #docregion setStyles
Map styles = {
'font-style': 'normal',
'font-weight': 'normal',
'font-size': 'smaller'
};
// #enddocregion setStyles
void callFax(String value) {
alerter('Faxing $value ...');
}
Map styles2 = {
'fontStyle': 'normal',
'fontWeight': 'normal',
'fontSize': 'smaller'
};
void callPhone(String value) {
alerter('Calling $value ...');
}
void alerter(String msg) => window.alert(msg);
void callFax(String value) => alerter('Faxing $value ...');
void callPhone(String value) => alerter('Calling $value ...');
void colorToggle() {
color = (color == Color.Red) ? Color.Blue : Color.Red;
color = (color == Color.red) ? Color.blue : Color.red;
}
int getVal() => val;
@ -97,7 +103,9 @@ class AppComponent {
alerter('Click me. $evtMsg');
}
void deleteHero([Hero hero]) => alerter('Deleted hero: ${hero?.firstName}');
void deleteHero([Hero hero]) {
alerter('Deleted hero: ${hero?.firstName}');
}
bool onSave([MouseEvent event = null]) {
var evtMsg =
@ -122,22 +130,31 @@ class AppComponent {
return JSON.encode(showStyles);
}
Map<String, bool> _previousClasses = {};
// #docregion setClasses
Map setClasses() {
classes['saveable'] = canSave; // true
classes['modified'] = !isUnchanged; // false
classes['special'] = isSpecial; // true
Map<String, bool> setClasses() {
final classes = {
'saveable': canSave, // true
'modified': !isUnchanged, // false
'special': isSpecial // true
};
// #docregion setClasses
// compensate for DevMode (sigh)
if (JSON.encode(_previousClasses) ==
JSON.encode(classes)) return _previousClasses;
_previousClasses = classes;
// #enddocregion setClasses
return classes;
}
// #enddocregion setClasses
// #docregion setStyles
Map setStyles() {
styles['font-style'] = canSave ? 'italic' : 'normal'; // italic
styles['font-weight'] = !isUnchanged ? 'bold' : 'normal'; // normal
styles['font-size'] = isSpecial ? '24px' : '8px'; // 24px
return styles;
return {
'font-style': canSave ? 'italic' : 'normal', // italic
'font-weight': !isUnchanged ? 'bold' : 'normal', // normal
'font-size': isSpecial ? '24px' : '8px' // 24px
};
}
// #enddocregion setStyles
@ -146,58 +163,72 @@ class AppComponent {
String toeChooser(Element picker) {
List<Element> choices = picker.children;
for (var i = 0; i < choices.length; i++) {
var choice = choices[i];
var choice = choices[i] as CheckboxInputElement;
if (choice.checked) {
toeChoice = choice.value;
return toeChoice;
}
}
return null;
}
// #docregion trackByHeroes
int trackByHeroes(int index, Hero hero) { return hero.id; }
int trackByHeroes(int index, Hero hero) => hero.id;
// #enddocregion trackByHeroes
// #docregion trackById
int trackById(int index, Map item): string { return item['id']; }
int trackById(int index, dynamic item) => item.id;
// #enddocregion trackById
int val = 2;
//////// Detect effects of NgForTrackBy ///////////////
int heroesNoTrackByChangeCount = 0;
int heroesWithTrackByChangeCount = 0;
/*
// Convert to Dart
@ViewChildren('noTrackBy') childrenNoTrackBy:QueryList<ElementRef>;
@ViewChildren('withTrackBy') childrenWithTrackBy:QueryList<ElementRef>;
private _oldNoTrackBy:HTMLElement[];
private _oldWithTrackBy:HTMLElement[];
@ViewChildren('noTrackBy') QueryList<ElementRef> childrenNoTrackBy;
@ViewChildren('withTrackBy') QueryList<ElementRef> childrenWithTrackBy;
private _detectNgForTrackByEffects() {
this._oldNoTrackBy = toArray(this.childrenNoTrackBy);
this._oldWithTrackBy = toArray(this.childrenWithTrackBy);
void _detectNgForTrackByEffects() {
/// Converts [viewChildren] to a list of [Element].
List<Element> _extractChildren(QueryList<ElementRef> viewChildren) =>
viewChildren.toList()[0].nativeElement.children.toList() as List<Element>;
this.childrenNoTrackBy.changes.subscribe((changes:any) => {
let newNoTrackBy = toArray(changes);
let isSame = this._oldNoTrackBy.every((v:any, i:number) => v === newNoTrackBy[i]);
if (!isSame) {
this._oldNoTrackBy = newNoTrackBy;
this.heroesNoTrackByChangeCount++;
}
})
{
// Updates 'without TrackBy' statistics.
List<Element> _oldNoTrackBy = _extractChildren(this.childrenNoTrackBy);
this.childrenWithTrackBy.changes.subscribe((changes:any) => {
let newWithTrackBy = toArray(changes);
let isSame = this._oldWithTrackBy.every((v:any, i:number) => v === newWithTrackBy[i]);
if (!isSame) {
this._oldWithTrackBy = newWithTrackBy;
this.heroesWithTrackByChangeCount++;
}
})
this.childrenNoTrackBy.changes.listen((Iterable<ElementRef> changes) {
final newNoTrackBy = _extractChildren(changes);
final isSame = newNoTrackBy.fold(true, (bool isSame, Element elt) {
return isSame && _oldNoTrackBy.contains(elt);
});
if (!isSame) {
_oldNoTrackBy = newNoTrackBy;
this.heroesNoTrackByChangeCount++;
}
});
}
{
// Updates 'with TrackBy' statistics.
List<Element> _oldWithTrackBy =
_extractChildren(this.childrenWithTrackBy);
this.childrenWithTrackBy.changes.listen((Iterable<ElementRef> changes) {
final newWithTrackBy = _extractChildren(changes);
final isSame = newWithTrackBy.fold(true, (bool isSame, Element elt) {
return isSame && _oldWithTrackBy.contains(elt);
});
if (!isSame) {
_oldWithTrackBy = newWithTrackBy;
this.heroesWithTrackByChangeCount++;
}
});
}
}
*/
///////////////////
}

View File

@ -188,11 +188,13 @@ button</button>
BAD!
HeroDetailComponent.hero expects a Hero object,
not the string "currentHero"
-->
<hero-detail hero="currentHero"></hero-detail>
<hero-detail hero="currentHero"></hero-detail>
In checked mode, uncommenting the hero-detail above causes this:
EXCEPTION: type 'String' is not a subtype of type 'Hero' of 'value'. -->
<!-- #enddocregion property-binding-6 -->
<!-- In checked mode, uncommenting the hero-detail above causes this:
EXCEPTION: type 'String' is not a subtype of type 'Hero' of 'value'. -->
<!-- #docregion property-binding-7 -->
<hero-detail prefix="You are my" [hero]="currentHero"></hero-detail>
<!-- #enddocregion property-binding-7 -->
@ -503,10 +505,10 @@ bindon-ngModel
<!-- #enddocregion NgSwitch -->
<!-- with <template> -->
<template [ngSwitchWhen]="'Eenie'"><span>Eenie</span></template>
<template [ngSwitchWhen]="'Meanie'"><span>Meanie</span></template>
<template [ngSwitchWhen]="'Miney'"><span>Miney</span></template>
<template [ngSwitchWhen]="'Moe'"><span>Moe</span></template>
<template ngSwitchWhen="Eenie"><span>Eenie</span></template>
<template ngSwitchWhen="Meanie"><span>Meanie</span></template>
<template ngSwitchWhen="Miney"><span>Miney</span></template>
<template ngSwitchWhen="Moe"><span>Moe</span></template>
<template ngSwitchDefault><span>other</span></template>
<!-- #docregion NgSwitch -->
@ -582,7 +584,7 @@ bindon-ngModel
</div>
<p>with trackBy and <i>space</i> separator</p>
<div #withTrackBy class="box">
<div class="box">
<div *ngFor="#hero of heroes trackBy:trackByHeroes">({{hero.id}}) {{hero.fullName}}</div>
</div>
@ -643,7 +645,7 @@ bindon-ngModel
<div class="box">
<!-- ngFor w/ hero-detail Component inside a template element -->
<!-- #docregion Template-4 -->
<template ngFor #hero [ngForOf]="heroes" [ngForTrackBy]="trackByHeroes>
<template ngFor #hero [ngForOf]="heroes" [ngForTrackBy]="trackByHeroes">
<hero-detail [hero]="hero"></hero-detail>
</template>
<!-- #enddocregion Template-4 -->
@ -723,13 +725,11 @@ bindon-ngModel
<!-- #enddocregion pipes-3 -->
<!-- #docregion pipes-json -->
<!-- Don't suggest using json for debugging; you'd probably use toString() instead.
<!-- We don't suggest using json for debugging; you'd probably use toString() instead.
Is there a good use for the json pipe in Dart? -->
<!--<div>{{currentHero | json}}</div>-->
<!-- #enddocregion pipes-json -->
<div>Birthdate: {{(currentHero?.birthdate | date:'longDate') | uppercase}}</div>
<div>

View File

@ -2,33 +2,36 @@
class Hero {
static int _nextId = 1;
int id;
final int id;
String firstName;
String lastName;
DateTime birthdate;
String url;
int rate = 100;
Hero(this.firstName, {this.lastName, this.birthdate, this.url, this.rate}) {
id = _nextId++;
}
static List<Hero> MockHeroes = [
new Hero('Hercules',
lastName: 'Son of Zeus',
birthdate: new DateTime(1970, 2, 25),
url: 'http://www.imdb.com/title/tt0065832/',
rate: 325),
new Hero('eenie', lastName: 'toe'),
new Hero('Meanie', lastName: 'Toe'),
new Hero('Miny', lastName: 'Toe'),
new Hero('Moe', lastName: 'Toe')
];
Hero(this.firstName,
{this.lastName, this.birthdate, this.url, this.rate, int id})
: this.id = id ?? _nextId++;
String get fullName {
if (lastName == null) return firstName;
return '$firstName $lastName';
}
String toString() => '$fullName (rate: $rate)';
Hero clone() => new Hero(firstName,
lastName: lastName, birthdate: birthdate, url: url, rate: rate, id: id);
@override String toString() => '$fullName (rate: $rate)';
}
final List<Hero> mockHeroes = [
new Hero('Hercules',
lastName: 'Son of Zeus',
birthdate: new DateTime(1970, 2, 25),
url: 'http://www.imdb.com/title/tt0065832/',
rate: 325),
new Hero('eenie', lastName: 'toe'),
new Hero('Meanie', lastName: 'Toe'),
new Hero('Miny', lastName: 'Toe'),
new Hero('Moe', lastName: 'Toe')
];

View File

@ -15,7 +15,9 @@ var nextHeroDetailId = 1;
inputs: const ['hero'],
outputs: const ['deleteRequest'],
// #enddocregion input-output-2
styles:['button { margin-left: 8px} div {margin: 8px 0} img {height:24px}'],
styles: const [
'button { margin-left: 8px} div {margin: 8px 0} img {height:24px}'
],
// #docregion template-1
template: '''
<div>
@ -24,8 +26,7 @@ var nextHeroDetailId = 1;
{{prefix}} {{hero?.fullName}}
</span>
<button (click)="delete()">Delete</button>
</div>
'''
</div>'''
// #enddocregion template-1
// #docregion input-output-2
)
@ -38,9 +39,9 @@ class HeroDetailComponent {
// #docregion deleteRequest
// This component make a request but it can't actually delete a hero.
final EventEmitter deleteRequest = new EventEmitter<Hero>();
final deleteRequest = new EventEmitter<Hero>();
delete() {
void delete() {
deleteRequest.emit(hero);
// #enddocregion deleteRequest
lineThrough = (lineThrough == '') ? 'line-through' : '';
@ -56,27 +57,26 @@ class HeroDetailComponent {
outputs: ['deleteRequest'],
*/
template: '''
<div style="border: 1px solid black; padding:3px">
<img src="{{heroImageUrl}}" style="float:left; margin-right:8px;">
<div><b>{{hero?.fullName}}</b></div>
<div>First: {{hero?.firstName}}</div>
<div>Last: {{hero?.lastName}}</div>
<div>Birthdate: {{hero?.birthdate | date:'longDate'}}</div>
<div>Web: <a href="{{hero?.url}}" target="_blank">{{hero?.url}}</a></div>
<div>Rate/hr: {{hero?.rate | currency:'EUR'}}</div>
<br clear="all">
<button (click)="delete()">Delete</button>
</div>
''')
<div style="border: 1px solid black; padding:3px">
<img src="{{heroImageUrl}}" style="float:left; margin-right:8px;">
<div><b>{{hero?.fullName}}</b></div>
<div>First: {{hero?.firstName}}</div>
<div>Last: {{hero?.lastName}}</div>
<div>Birthdate: {{hero?.birthdate | date:'longDate'}}</div>
<div>Web: <a href="{{hero?.url}}" target="_blank">{{hero?.url}}</a></div>
<div>Rate/hr: {{hero?.rate | currency:'EUR'}}</div>
<br clear="all">
<button (click)="delete()">Delete</button>
</div>''')
class BigHeroDetailComponent extends HeroDetailComponent {
// #docregion input-output-1
@Input() Hero hero;
@Output() final EventEmitter deleteRequest = new EventEmitter<Hero>();
@Output() final deleteRequest = new EventEmitter<Hero>();
// #enddocregion input-output-1
String heroImageUrl = 'assets/images/hero.png';
String get heroImageUrl => 'assets/images/hero.png';
delete() {
@override void delete() {
deleteRequest.emit(hero);
}
}

View File

@ -16,4 +16,5 @@ transformers:
- 'package:angular2/common.dart#FORM_DIRECTIVES'
entry_points: web/main.dart
- dart_to_js_script_rewriter
- $dart2js:
checked: true

View File

@ -2,6 +2,6 @@
import 'package:angular2/bootstrap.dart';
import 'package:template_syntax/app_component.dart';
main() {
void main() {
bootstrap(AppComponent);
}