samples(template-syntax/dart): fix sample & make it comply with style guidelines
closes #879
This commit is contained in:
parent
f01dc81fa1
commit
d9b55cb9ac
|
@ -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
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
*/
|
||||
///////////////////
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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')
|
||||
];
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,4 +16,5 @@ transformers:
|
|||
- 'package:angular2/common.dart#FORM_DIRECTIVES'
|
||||
entry_points: web/main.dart
|
||||
- dart_to_js_script_rewriter
|
||||
|
||||
- $dart2js:
|
||||
checked: true
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
import 'package:angular2/bootstrap.dart';
|
||||
import 'package:template_syntax/app_component.dart';
|
||||
|
||||
main() {
|
||||
void main() {
|
||||
bootstrap(AppComponent);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue