diff --git a/public/docs/_examples/template-syntax/dart/.analysis_options b/public/docs/_examples/template-syntax/dart/.analysis_options index 4fcc97bfe6..d8c582e96f 100644 --- a/public/docs/_examples/template-syntax/dart/.analysis_options +++ b/public/docs/_examples/template-syntax/dart/.analysis_options @@ -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 diff --git a/public/docs/_examples/template-syntax/dart/lib/app_component.dart b/public/docs/_examples/template-syntax/dart/lib/app_component.dart index 2a4f4ba37e..795623ca04 100644 --- a/public/docs/_examples/template-syntax/dart/lib/app_component.dart +++ b/public/docs/_examples/template-syntax/dart/lib/app_component.dart @@ -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 heroes = Hero.MockHeroes; - Hero selectedHero = Hero.MockHeroes[0]; - Hero currentHero = Hero.MockHeroes[0]; + Color color = Color.red; + + List 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 _previousClasses = {}; // #docregion setClasses - Map setClasses() { - classes['saveable'] = canSave; // true - classes['modified'] = !isUnchanged; // false - classes['special'] = isSpecial; // true - + Map 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 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; - @ViewChildren('withTrackBy') childrenWithTrackBy:QueryList; - private _oldNoTrackBy:HTMLElement[]; - private _oldWithTrackBy:HTMLElement[]; + @ViewChildren('noTrackBy') QueryList childrenNoTrackBy; + @ViewChildren('withTrackBy') QueryList childrenWithTrackBy; - private _detectNgForTrackByEffects() { - this._oldNoTrackBy = toArray(this.childrenNoTrackBy); - this._oldWithTrackBy = toArray(this.childrenWithTrackBy); + void _detectNgForTrackByEffects() { + /// Converts [viewChildren] to a list of [Element]. + List _extractChildren(QueryList viewChildren) => + viewChildren.toList()[0].nativeElement.children.toList() as List; - 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 _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 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 _oldWithTrackBy = + _extractChildren(this.childrenWithTrackBy); + + this.childrenWithTrackBy.changes.listen((Iterable 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++; + } + }); + } } - */ /////////////////// } diff --git a/public/docs/_examples/template-syntax/dart/lib/app_component.html b/public/docs/_examples/template-syntax/dart/lib/app_component.html index 41c2f8c970..7c513d69ff 100644 --- a/public/docs/_examples/template-syntax/dart/lib/app_component.html +++ b/public/docs/_examples/template-syntax/dart/lib/app_component.html @@ -188,11 +188,13 @@ button BAD! HeroDetailComponent.hero expects a Hero object, not the string "currentHero" - --> - + + + + In checked mode, uncommenting the hero-detail above causes this: + EXCEPTION: type 'String' is not a subtype of type 'Hero' of 'value'. --> - + @@ -503,10 +505,10 @@ bindon-ngModel - - - - + + + + @@ -582,7 +584,7 @@ bindon-ngModel

with trackBy and space separator

-
+
({{hero.id}}) {{hero.fullName}}
@@ -643,7 +645,7 @@ bindon-ngModel
- @@ -723,13 +725,11 @@ bindon-ngModel - - -
Birthdate: {{(currentHero?.birthdate | date:'longDate') | uppercase}}
diff --git a/public/docs/_examples/template-syntax/dart/lib/hero.dart b/public/docs/_examples/template-syntax/dart/lib/hero.dart index 23adafb866..d366a23c19 100644 --- a/public/docs/_examples/template-syntax/dart/lib/hero.dart +++ b/public/docs/_examples/template-syntax/dart/lib/hero.dart @@ -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 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 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') +]; diff --git a/public/docs/_examples/template-syntax/dart/lib/hero_detail_component.dart b/public/docs/_examples/template-syntax/dart/lib/hero_detail_component.dart index 1b9a85e5a9..80130e0b18 100644 --- a/public/docs/_examples/template-syntax/dart/lib/hero_detail_component.dart +++ b/public/docs/_examples/template-syntax/dart/lib/hero_detail_component.dart @@ -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: '''
@@ -24,8 +26,7 @@ var nextHeroDetailId = 1; {{prefix}} {{hero?.fullName}} -
-''' +
''' // #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(); + final deleteRequest = new EventEmitter(); - delete() { + void delete() { deleteRequest.emit(hero); // #enddocregion deleteRequest lineThrough = (lineThrough == '') ? 'line-through' : ''; @@ -56,27 +57,26 @@ class HeroDetailComponent { outputs: ['deleteRequest'], */ template: ''' -
- -
{{hero?.fullName}}
-
First: {{hero?.firstName}}
-
Last: {{hero?.lastName}}
-
Birthdate: {{hero?.birthdate | date:'longDate'}}
- -
Rate/hr: {{hero?.rate | currency:'EUR'}}
-
- -
-''') +
+ +
{{hero?.fullName}}
+
First: {{hero?.firstName}}
+
Last: {{hero?.lastName}}
+
Birthdate: {{hero?.birthdate | date:'longDate'}}
+ +
Rate/hr: {{hero?.rate | currency:'EUR'}}
+
+ +
''') class BigHeroDetailComponent extends HeroDetailComponent { // #docregion input-output-1 @Input() Hero hero; - @Output() final EventEmitter deleteRequest = new EventEmitter(); + @Output() final deleteRequest = new EventEmitter(); // #enddocregion input-output-1 - String heroImageUrl = 'assets/images/hero.png'; + String get heroImageUrl => 'assets/images/hero.png'; - delete() { + @override void delete() { deleteRequest.emit(hero); } } diff --git a/public/docs/_examples/template-syntax/dart/pubspec.yaml b/public/docs/_examples/template-syntax/dart/pubspec.yaml index 95a6020231..65baaf3f09 100644 --- a/public/docs/_examples/template-syntax/dart/pubspec.yaml +++ b/public/docs/_examples/template-syntax/dart/pubspec.yaml @@ -16,4 +16,5 @@ transformers: - 'package:angular2/common.dart#FORM_DIRECTIVES' entry_points: web/main.dart - dart_to_js_script_rewriter - +- $dart2js: + checked: true diff --git a/public/docs/_examples/template-syntax/dart/web/main.dart b/public/docs/_examples/template-syntax/dart/web/main.dart index 771958fea6..f1659d0821 100644 --- a/public/docs/_examples/template-syntax/dart/web/main.dart +++ b/public/docs/_examples/template-syntax/dart/web/main.dart @@ -2,6 +2,6 @@ import 'package:angular2/bootstrap.dart'; import 'package:template_syntax/app_component.dart'; -main() { +void main() { bootstrap(AppComponent); }