docs(guide/lifecycle-hooks): add Dart version of example
NOTE: The Dart version generates fewer lifecycle events than the TS version. See angular/angular#6498 for details. closes #733
This commit is contained in:
parent
6ee3756989
commit
c4ae1f1b1b
|
@ -0,0 +1,94 @@
|
||||||
|
// #docregion
|
||||||
|
import 'package:angular2/angular2.dart';
|
||||||
|
import 'logger_service.dart';
|
||||||
|
import 'child_component.dart';
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'after-content',
|
||||||
|
template: '''
|
||||||
|
<div class="after-content">
|
||||||
|
<div>-- child content begins --</div>
|
||||||
|
|
||||||
|
<ng-content></ng-content>
|
||||||
|
|
||||||
|
<div>-- child content ends --</div>
|
||||||
|
</div>
|
||||||
|
''',
|
||||||
|
styles: const ['.after-content {background: LightCyan; padding: 8px;}'])
|
||||||
|
class AfterContentComponent
|
||||||
|
implements AfterContentChecked, AfterContentInit, AfterViewInit {
|
||||||
|
LoggerService _logger;
|
||||||
|
|
||||||
|
// Query for a CONTENT child of type `ChildComponent`
|
||||||
|
@ContentChild(ChildComponent) ChildComponent contentChild;
|
||||||
|
|
||||||
|
// Query for a VIEW child of type`ChildComponent`
|
||||||
|
// No such VIEW child exists!
|
||||||
|
// This component holds content but no view of that type.
|
||||||
|
@ViewChild(ChildComponent) ChildComponent viewChild;
|
||||||
|
|
||||||
|
String _prevHero;
|
||||||
|
|
||||||
|
AfterContentComponent(this._logger) {
|
||||||
|
_logger.log('AfterContent ctor: $message');
|
||||||
|
}
|
||||||
|
|
||||||
|
///// Hooks
|
||||||
|
ngAfterContentInit() {
|
||||||
|
// contentChild is set after the content has been initialized
|
||||||
|
_logger.log('AfterContentInit: $message');
|
||||||
|
}
|
||||||
|
|
||||||
|
get hasViewChild => viewChild != null;
|
||||||
|
|
||||||
|
ngAfterViewInit() {
|
||||||
|
_logger
|
||||||
|
.log('AfterViewInit: There is ${hasViewChild ? 'a' : 'no'} view child');
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterContentChecked() {
|
||||||
|
// contentChild is updated after the content has been checked
|
||||||
|
// Called frequently; only report when the hero changes
|
||||||
|
if (!hasContentChild || _prevHero == contentChild.hero) return;
|
||||||
|
_prevHero = contentChild.hero;
|
||||||
|
_logger.log('AfterContentChecked: $message');
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get hasContentChild => contentChild != null;
|
||||||
|
|
||||||
|
String get message => hasContentChild
|
||||||
|
? '"${contentChild.hero}" child content'
|
||||||
|
: 'no child content';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'after-content-parent',
|
||||||
|
template: '''
|
||||||
|
<div class="parent">
|
||||||
|
<h2>AfterContent</h2>
|
||||||
|
|
||||||
|
<after-content>
|
||||||
|
<input [(ngModel)]="hero">
|
||||||
|
<button (click)="showChild = !showChild">Toggle child view</button>
|
||||||
|
|
||||||
|
<my-child *ngIf="showChild" [hero]="hero"></my-child>
|
||||||
|
</after-content>
|
||||||
|
|
||||||
|
<h4>-- Lifecycle Hook Log --</h4>
|
||||||
|
<div *ngFor="#msg of hookLog">{{msg}}</div>
|
||||||
|
</div>
|
||||||
|
''',
|
||||||
|
styles: const [
|
||||||
|
'.parent {background: powderblue; padding: 8px; margin:100px 8px;}'
|
||||||
|
],
|
||||||
|
directives: const [AfterContentComponent, ChildComponent],
|
||||||
|
providers: const [LoggerService])
|
||||||
|
class AfterContentParentComponent {
|
||||||
|
List<String> hookLog;
|
||||||
|
String hero = 'Magneta';
|
||||||
|
bool showChild = true;
|
||||||
|
|
||||||
|
AfterContentParentComponent(LoggerService logger) {
|
||||||
|
hookLog = logger.logs;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
// #docregion
|
||||||
|
import 'package:angular2/angular2.dart';
|
||||||
|
import 'child_component.dart';
|
||||||
|
import 'logger_service.dart';
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'after-view-parent',
|
||||||
|
template: '''
|
||||||
|
<div class="parent">
|
||||||
|
<h2>AfterView</h2>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input [(ngModel)]="hero">
|
||||||
|
<button (click)="showChild = !showChild">Toggle child view</button>
|
||||||
|
|
||||||
|
<my-child *ngIf="showChild" [hero]="hero"></my-child>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4>-- Lifecycle Hook Log --</h4>
|
||||||
|
<div *ngFor="#msg of hookLog">{{msg}}</div>
|
||||||
|
</div>
|
||||||
|
''',
|
||||||
|
styles: const [
|
||||||
|
'.parent {background: burlywood; padding: 8px; margin:100px 8px;}'
|
||||||
|
],
|
||||||
|
directives: const [ChildComponent],
|
||||||
|
providers: const [LoggerService])
|
||||||
|
class AfterViewParentComponent
|
||||||
|
implements AfterContentInit, AfterViewChecked, AfterViewInit {
|
||||||
|
LoggerService _logger;
|
||||||
|
List<String> hookLog;
|
||||||
|
String hero = 'Magneta';
|
||||||
|
bool showChild = true;
|
||||||
|
|
||||||
|
// Query for a CONTENT child of type `ChildComponent`
|
||||||
|
// No such CONTENT child exists!
|
||||||
|
// This component holds a view but no content of that type.
|
||||||
|
@ContentChild(ChildComponent)
|
||||||
|
ChildComponent contentChild;
|
||||||
|
|
||||||
|
// Query for a VIEW child of type `ChildComponent`
|
||||||
|
@ViewChild(ChildComponent)
|
||||||
|
ChildComponent viewChild;
|
||||||
|
|
||||||
|
String _prevHero;
|
||||||
|
|
||||||
|
AfterViewParentComponent(this._logger) {
|
||||||
|
hookLog = _logger.logs;
|
||||||
|
_logger.log('AfterView ctor: $message');
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get _hasContentChild => contentChild != null;
|
||||||
|
bool get _hasViewChild => viewChild != null;
|
||||||
|
|
||||||
|
///// Hooks
|
||||||
|
ngAfterContentInit() {
|
||||||
|
_logger.log(
|
||||||
|
'AfterContentInit: There is ${ _hasContentChild ? 'a' : 'no'} content child');
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit() {
|
||||||
|
// viewChild is set after the view has been initialized
|
||||||
|
_logger.log('AfterViewInit: $message');
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewChecked() {
|
||||||
|
// viewChild is updated after the view has been checked
|
||||||
|
// Called frequently; only report when the hero changes
|
||||||
|
if (!_hasViewChild || _prevHero == viewChild.hero) return;
|
||||||
|
_prevHero = viewChild.hero;
|
||||||
|
_logger.log('AfterViewChecked: $message');
|
||||||
|
}
|
||||||
|
|
||||||
|
String get message =>
|
||||||
|
_hasViewChild ? '"${viewChild.hero}" child view' : 'no child view';
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
// #docregion
|
||||||
|
import 'package:angular2/angular2.dart';
|
||||||
|
import 'peek_a_boo_parent_component.dart';
|
||||||
|
import 'on_changes_component.dart';
|
||||||
|
import 'after_view_component.dart';
|
||||||
|
import 'after_content_parent.dart';
|
||||||
|
import 'spy_component.dart';
|
||||||
|
import 'counter_component.dart';
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'my-app',
|
||||||
|
template: '''
|
||||||
|
<peek-a-boo-parent></peek-a-boo-parent>
|
||||||
|
<on-changes-parent></on-changes-parent>
|
||||||
|
<after-view-parent></after-view-parent>
|
||||||
|
<after-content-parent></after-content-parent>
|
||||||
|
<spy-parent></spy-parent>
|
||||||
|
<counter-parent></counter-parent>
|
||||||
|
''',
|
||||||
|
directives: const [
|
||||||
|
PeekABooParentComponent,
|
||||||
|
OnChangesParentComponent,
|
||||||
|
AfterViewParentComponent,
|
||||||
|
AfterContentParentComponent,
|
||||||
|
SpyParentComponent,
|
||||||
|
CounterParentComponent
|
||||||
|
])
|
||||||
|
class AppComponent {}
|
|
@ -0,0 +1,19 @@
|
||||||
|
// #docregion
|
||||||
|
import 'package:angular2/angular2.dart';
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'my-child',
|
||||||
|
template: '''
|
||||||
|
<div class="my-child">
|
||||||
|
<div>-- child view begins --</div>
|
||||||
|
<div class="child">{{hero}} is my hero.</div>
|
||||||
|
<div>-- child view ends --</div>
|
||||||
|
</div>
|
||||||
|
''',
|
||||||
|
styles: const [
|
||||||
|
'.child {background: Yellow; padding: 8px; }',
|
||||||
|
'.my-child {background: LightYellow; padding: 8px; margin-top: 8px}'
|
||||||
|
])
|
||||||
|
class ChildComponent {
|
||||||
|
@Input() String hero;
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
// #docregion
|
||||||
|
import 'package:angular2/angular2.dart';
|
||||||
|
import 'spy_directive.dart';
|
||||||
|
import 'logger_service.dart';
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'my-counter',
|
||||||
|
template: '''
|
||||||
|
<div class="counter">
|
||||||
|
Counter = {{counter}}
|
||||||
|
|
||||||
|
<h5>-- Counter Change Log --</h5>
|
||||||
|
<div *ngFor="#chg of changeLog" mySpy>{{chg}}</div>
|
||||||
|
</div>
|
||||||
|
''',
|
||||||
|
styles: const [
|
||||||
|
'.counter {background: LightYellow; padding: 8px; margin-top: 8px}'
|
||||||
|
],
|
||||||
|
directives: const [Spy])
|
||||||
|
class MyCounter implements OnChanges {
|
||||||
|
@Input() num counter;
|
||||||
|
List<String> changeLog = [];
|
||||||
|
|
||||||
|
ngOnChanges(Map<String, SimpleChange> changes) {
|
||||||
|
// Empty the changeLog whenever counter goes to zero
|
||||||
|
// hint: this is a way to respond programmatically to external value changes.
|
||||||
|
if (this.counter == 0) {
|
||||||
|
changeLog.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// A change to `counter` is the only change we care about
|
||||||
|
SimpleChange prop = changes['counter'];
|
||||||
|
var prev = prop.isFirstChange() ? "{}" : prop.previousValue;
|
||||||
|
changeLog.add(
|
||||||
|
'counter: currentValue = ${prop.currentValue}, previousValue = $prev');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'counter-parent',
|
||||||
|
template: '''
|
||||||
|
<div class="parent">
|
||||||
|
<h2>Counter Spy</h2>
|
||||||
|
|
||||||
|
<button (click)="updateCounter()">Update counter</button>
|
||||||
|
<button (click)="reset()">Reset Counter</button>
|
||||||
|
|
||||||
|
<my-counter [counter]="value"></my-counter>
|
||||||
|
|
||||||
|
<h4>-- Spy Lifecycle Hook Log --</h4>
|
||||||
|
<div *ngFor="#msg of spyLog">{{msg}}</div>
|
||||||
|
</div>
|
||||||
|
''',
|
||||||
|
styles: const [
|
||||||
|
'.parent {background: gold; padding: 10px; margin:100px 8px;}'
|
||||||
|
],
|
||||||
|
directives: const [MyCounter],
|
||||||
|
providers: const [LoggerService])
|
||||||
|
class CounterParentComponent {
|
||||||
|
num value;
|
||||||
|
List<String> spyLog = [];
|
||||||
|
|
||||||
|
LoggerService _logger;
|
||||||
|
|
||||||
|
CounterParentComponent(this._logger) {
|
||||||
|
spyLog = _logger.logs;
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCounter() => value += 1;
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
_logger.log('-- reset --');
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
import 'package:angular2/angular2.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
class LoggerService {
|
||||||
|
List<String> logs = [];
|
||||||
|
|
||||||
|
log(String msg, [bool noTick = false]) {
|
||||||
|
if (!noTick) {
|
||||||
|
tick();
|
||||||
|
}
|
||||||
|
logs.add(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() => logs.clear();
|
||||||
|
|
||||||
|
tick() => new Future(() {});
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
// #docregion
|
||||||
|
import 'package:angular2/angular2.dart';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
class Hero {
|
||||||
|
String name;
|
||||||
|
Hero(this.name);
|
||||||
|
|
||||||
|
Map toJson() => {'name': name};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'my-hero',
|
||||||
|
template: '''
|
||||||
|
<div class="hero">
|
||||||
|
<p>{{hero.name}} can {{power}}</p>
|
||||||
|
|
||||||
|
<h4>-- Change Log --</h4>
|
||||||
|
<div *ngFor="#chg of changeLog">{{chg}}</div>
|
||||||
|
</div>
|
||||||
|
''',
|
||||||
|
styles: const [
|
||||||
|
'.hero {background: LightYellow; padding: 8px; margin-top: 8px}',
|
||||||
|
'p {background: Yellow; padding: 8px; margin-top: 8px}'
|
||||||
|
])
|
||||||
|
class MyHeroComponent implements OnChanges {
|
||||||
|
@Input() Hero hero;
|
||||||
|
@Input() String power;
|
||||||
|
@Input() bool reset;
|
||||||
|
List<String> changeLog = [];
|
||||||
|
|
||||||
|
ngOnChanges(Map<String, SimpleChange> changes) {
|
||||||
|
// Empty the changeLog whenever 'reset' property changes
|
||||||
|
// hint: this is a way to respond programmatically to external value changes.
|
||||||
|
if (changes.containsKey('reset')) changeLog.clear();
|
||||||
|
|
||||||
|
changes.forEach((String key, SimpleChange change) {
|
||||||
|
String cur = JSON.encode(change.currentValue);
|
||||||
|
String prev =
|
||||||
|
change.isFirstChange() ? "{}" : JSON.encode(change.previousValue);
|
||||||
|
changeLog.add('$key: currentValue = ${cur}, previousValue = $prev');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'on-changes-parent',
|
||||||
|
template: '''
|
||||||
|
<div class="parent">
|
||||||
|
<h2>OnChanges</h2>
|
||||||
|
|
||||||
|
<div>Hero.name: <input [(ngModel)]="hero.name"> <i>does NOT trigger onChanges</i></div>
|
||||||
|
<div>Power: <input [(ngModel)]="power"> <i>DOES trigger onChanges</i></div>
|
||||||
|
<div><button (click)="reset()">Reset Log</button> <i>triggers onChanges and clears the change log</i></div>
|
||||||
|
|
||||||
|
<my-hero [hero]="hero" [power]="power" [reset]="resetTrigger"></my-hero>
|
||||||
|
</div>
|
||||||
|
''',
|
||||||
|
styles: const [
|
||||||
|
'.parent {background: Lavender; padding: 10px; margin:100px 8px;}'
|
||||||
|
],
|
||||||
|
directives: const [MyHeroComponent])
|
||||||
|
class OnChangesParentComponent {
|
||||||
|
Hero hero;
|
||||||
|
String power;
|
||||||
|
bool resetTrigger = false;
|
||||||
|
|
||||||
|
OnChangesParentComponent() {
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
// new Hero object every time; triggers onChange
|
||||||
|
hero = new Hero('Windstorm');
|
||||||
|
// setting power only triggers onChange if this value is different
|
||||||
|
power = 'sing';
|
||||||
|
// always triggers onChange ... which is interpreted as a reset
|
||||||
|
resetTrigger = !resetTrigger;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
// #docregion
|
||||||
|
// #docregion lc-imports
|
||||||
|
import 'package:angular2/angular2.dart';
|
||||||
|
import 'package:lifecycle_hooks/logger_service.dart';
|
||||||
|
|
||||||
|
int nextId = 1;
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'peek-a-boo',
|
||||||
|
template: '<p>Now you see my hero, {{name}}</p>',
|
||||||
|
styles: const ['p {background: LightYellow; padding: 8px}'])
|
||||||
|
class PeekABooComponent
|
||||||
|
implements
|
||||||
|
OnChanges,
|
||||||
|
OnInit,
|
||||||
|
AfterContentInit,
|
||||||
|
AfterContentChecked,
|
||||||
|
AfterViewInit,
|
||||||
|
AfterViewChecked,
|
||||||
|
OnDestroy {
|
||||||
|
@Input() String name;
|
||||||
|
|
||||||
|
int _afterContentCheckedCounter = 1;
|
||||||
|
int _afterViewCheckedCounter = 1;
|
||||||
|
int _id = nextId++;
|
||||||
|
LoggerService _logger;
|
||||||
|
int _onChangesCounter = 1;
|
||||||
|
String _verb = 'initialized';
|
||||||
|
|
||||||
|
PeekABooComponent(this._logger);
|
||||||
|
|
||||||
|
// Only called if there is an @input variable set by parent.
|
||||||
|
ngOnChanges(Map<String, SimpleChange> changes) {
|
||||||
|
List<String> messages = [];
|
||||||
|
changes.forEach((String propName, SimpleChange change) {
|
||||||
|
if (propName == 'name') {
|
||||||
|
var name = changes['name'].currentValue;
|
||||||
|
messages.add('name $_verb to "$name"');
|
||||||
|
} else {
|
||||||
|
messages.add('$propName $_verb');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_logIt('onChanges (${_onChangesCounter++}): ${messages.join('; ')}');
|
||||||
|
_verb = 'changed'; // Next time it will be a change
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() => _logIt('onInit');
|
||||||
|
|
||||||
|
ngAfterContentInit() => _logIt('afterContentInit');
|
||||||
|
|
||||||
|
// Called after every change detection check
|
||||||
|
// of the component (directive) CONTENT
|
||||||
|
// Beware! Called frequently!
|
||||||
|
ngAfterContentChecked() {
|
||||||
|
int counter = _afterContentCheckedCounter++;
|
||||||
|
_logIt('afterContentChecked (${counter})');
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit() => _logIt('afterViewInit');
|
||||||
|
|
||||||
|
// Called after every change detection check
|
||||||
|
// of the component (directive) VIEW
|
||||||
|
// Beware! Called frequently!
|
||||||
|
ngAfterViewChecked() {
|
||||||
|
int counter = _afterViewCheckedCounter++;
|
||||||
|
_logIt('afterViewChecked ($counter)');
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() => _logIt('onDestroy');
|
||||||
|
|
||||||
|
_logIt(String msg) {
|
||||||
|
// Don't tick or else
|
||||||
|
// the AfterContentChecked and AfterViewChecked recurse.
|
||||||
|
// Let parent call tick()
|
||||||
|
_logger.log("#$_id $msg", true);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
// #docregion
|
||||||
|
import 'package:angular2/angular2.dart';
|
||||||
|
import 'package:lifecycle_hooks/logger_service.dart';
|
||||||
|
import 'package:lifecycle_hooks/peek_a_boo_component.dart';
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'peek-a-boo-parent',
|
||||||
|
template: '''
|
||||||
|
<div class="parent">
|
||||||
|
<h2>Peek-A-Boo</h2>
|
||||||
|
|
||||||
|
<button (click)="toggleChild()">
|
||||||
|
{{hasChild ? 'Destroy' : 'Create'}} PeekABooComponent
|
||||||
|
</button>
|
||||||
|
<button (click)="updateHero()" [hidden]="!hasChild">Update Hero</button>
|
||||||
|
|
||||||
|
<peek-a-boo *ngIf="hasChild" [name]="heroName">
|
||||||
|
</peek-a-boo>
|
||||||
|
|
||||||
|
<h4>-- Lifecycle Hook Log --</h4>
|
||||||
|
<div *ngFor="#msg of hookLog">{{msg}}</div>
|
||||||
|
</div>
|
||||||
|
''',
|
||||||
|
styles: const [
|
||||||
|
'.parent {background: moccasin; padding: 10px; margin:100px 8px}'
|
||||||
|
],
|
||||||
|
directives: const [PeekABooComponent],
|
||||||
|
providers: const [LoggerService])
|
||||||
|
class PeekABooParentComponent {
|
||||||
|
bool hasChild = false;
|
||||||
|
List<String> hookLog;
|
||||||
|
|
||||||
|
String heroName = 'Windstorm';
|
||||||
|
LoggerService _logger;
|
||||||
|
|
||||||
|
PeekABooParentComponent(this._logger) {
|
||||||
|
hookLog = _logger.logs;
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleChild() {
|
||||||
|
hasChild = !hasChild;
|
||||||
|
if (hasChild) {
|
||||||
|
heroName = 'Windstorm';
|
||||||
|
_logger.clear(); // clear log on create
|
||||||
|
}
|
||||||
|
_logger.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHero() {
|
||||||
|
heroName += '!';
|
||||||
|
_logger.tick();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
// #docregion
|
||||||
|
import 'package:angular2/angular2.dart';
|
||||||
|
import 'logger_service.dart';
|
||||||
|
import 'spy_directive.dart';
|
||||||
|
|
||||||
|
@Component(
|
||||||
|
selector: 'spy-parent',
|
||||||
|
template: '''
|
||||||
|
<div class="parent">
|
||||||
|
<h2>Spy Directive</h2>
|
||||||
|
|
||||||
|
<input [(ngModel)]="newName" (keyup.enter)="addHero()">
|
||||||
|
<button (click)="addHero()">Add Hero</button>
|
||||||
|
<button (click)="reset()">Reset Heroes</button>
|
||||||
|
|
||||||
|
<p></p>
|
||||||
|
<div *ngFor="#hero of heroes" mySpy class="heroes">
|
||||||
|
{{hero}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4>-- Spy Lifecycle Hook Log --</h4>
|
||||||
|
<div *ngFor="#msg of spyLog">{{msg}}</div>
|
||||||
|
</div>
|
||||||
|
''',
|
||||||
|
styles: const [
|
||||||
|
'.parent {background: khaki; padding: 10px; margin:100px 8px}',
|
||||||
|
'.heroes {background: LightYellow; padding: 0 8px}'
|
||||||
|
],
|
||||||
|
directives: const [Spy],
|
||||||
|
providers: const [LoggerService])
|
||||||
|
class SpyParentComponent {
|
||||||
|
String newName = 'Herbie';
|
||||||
|
List<String> heroes = ['Windstorm', 'Magneta'];
|
||||||
|
List<String> spyLog;
|
||||||
|
LoggerService _logger;
|
||||||
|
|
||||||
|
SpyParentComponent(this._logger) {
|
||||||
|
spyLog = _logger.logs;
|
||||||
|
}
|
||||||
|
|
||||||
|
addHero() {
|
||||||
|
if (newName.trim().isNotEmpty) {
|
||||||
|
heroes.add(newName.trim());
|
||||||
|
newName = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reset() {
|
||||||
|
_logger.log('-- reset --');
|
||||||
|
heroes.clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
// #docregion
|
||||||
|
import 'package:angular2/angular2.dart';
|
||||||
|
import 'logger_service.dart';
|
||||||
|
|
||||||
|
int nextId = 1;
|
||||||
|
|
||||||
|
// Spy on any element to which it is applied.
|
||||||
|
// Usage: <div mySpy>...</div>
|
||||||
|
@Directive(selector: '[mySpy]')
|
||||||
|
class Spy implements OnInit, OnDestroy {
|
||||||
|
int _id = nextId++;
|
||||||
|
LoggerService _logger;
|
||||||
|
|
||||||
|
Spy(this._logger);
|
||||||
|
|
||||||
|
ngOnInit() => _logIt('onInit');
|
||||||
|
|
||||||
|
ngOnDestroy() => _logIt('onDestroy');
|
||||||
|
|
||||||
|
_logIt(String msg) => _logger.log('Spy #$_id $msg');
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
name: lifecycle_hooks
|
||||||
|
description: Lifecycle Hooks
|
||||||
|
version: 0.0.1
|
||||||
|
environment:
|
||||||
|
sdk: '>=1.13.0 <2.0.0'
|
||||||
|
dependencies:
|
||||||
|
angular2: 2.0.0-beta.1
|
||||||
|
browser: ^0.10.0
|
||||||
|
dart_to_js_script_rewriter: ^0.1.0
|
||||||
|
transformers:
|
||||||
|
- angular2:
|
||||||
|
platform_directives:
|
||||||
|
- 'package:angular2/common.dart#CORE_DIRECTIVES'
|
||||||
|
- 'package:angular2/common.dart#FORM_DIRECTIVES'
|
||||||
|
entry_points: web/main.dart
|
||||||
|
- dart_to_js_script_rewriter
|
|
@ -0,0 +1,15 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<!-- #docregion -->
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Angular 2 Lifecycle Hooks</title>
|
||||||
|
<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>
|
|
@ -0,0 +1,7 @@
|
||||||
|
// #docregion
|
||||||
|
import 'package:angular2/bootstrap.dart';
|
||||||
|
import 'package:lifecycle_hooks/app_component.dart';
|
||||||
|
|
||||||
|
main() {
|
||||||
|
bootstrap(AppComponent);
|
||||||
|
}
|
Loading…
Reference in New Issue