From a110ce95dca79fb77ca2667f9a47ad88e47dc52d Mon Sep 17 00:00:00 2001 From: Victor Berchet Date: Thu, 24 Sep 2015 15:40:50 -0700 Subject: [PATCH] doc(LifecycleHooks): update API doc Closes #4357 --- .../angular2/src/core/linker/interfaces.ts | 396 ++++++++++++++---- 1 file changed, 318 insertions(+), 78 deletions(-) diff --git a/modules/angular2/src/core/linker/interfaces.ts b/modules/angular2/src/core/linker/interfaces.ts index 53362df056..f94f3044f1 100644 --- a/modules/angular2/src/core/linker/interfaces.ts +++ b/modules/angular2/src/core/linker/interfaces.ts @@ -1,6 +1,9 @@ import {StringMap, MapWrapper} from 'angular2/src/core/facade/collection'; import {SimpleChange} from 'angular2/src/core/change_detection/change_detection_util'; +/** + * @private + */ export enum LifecycleHooks { OnInit, OnDestroy, @@ -12,6 +15,9 @@ export enum LifecycleHooks { AfterViewChecked } +/** + * @private + */ export var LIFECYCLE_HOOKS_VALUES = [ LifecycleHooks.OnInit, LifecycleHooks.OnDestroy, @@ -30,156 +36,390 @@ export var LIFECYCLE_HOOKS_VALUES = [ * - `DoCheck`, * - `AfterContentInit`, * - `AfterContentChecked`, + * - `AfterViewInit`, + * - `AfterViewChecked`, * - `OnDestroy` (at the very end before destruction) */ /** - * Notify a directive when any of its bindings have changed. + * Implement this interface to get notified when any data-bound property of your directive changes. * - * `onChanges` is called right after the directive's bindings have been checked, - * and before any of its children's bindings have been checked. + * `onChanges` is called right after the data-bound properties have been checked and before view + * and content children are checked if at least one of them has changed. * - * It is invoked only if at least one of the directive's bindings has changed. + * The `changes` parameter contains an entry for each of the changed data-bound property. The key is + * the property name and the value is an instance of {@link SimpleChange}. * - * ## Example: + * ### Example ([live example](http://plnkr.co/edit/AHrB6opLqHDBPkt4KpdT?p=preview)): * - * ``` - * @Component(...) + * ```typescript + * @Component({selector: 'my-cmp'}) + * @View({template: `

myProp = {{myProp}}

`}) * class MyComponent implements OnChanges { - * propA; - * propB; + * @Property() myProp: any; * - * onChanges(changes: {[idx: string, PropertyUpdate]}): void { - * // This will get called after any of the inputs have been updated. - * if (changes['propA']) { - * // if propA was updated - * } - * if (changes['propA']) { - * // if propB was updated - * } + * onChanges(changes: {[propName: string]: SimpleChange}) { + * console.log('onChanges - myProp = ' + changes['myProp'].currentValue); * } * } - * ``` + * + * @Component({selector: 'app'}) + * @View({ + * template: ` + * + * `, + * directives: [MyComponent] + * }) + * export class App { + * value = 0; + * } + * + * bootstrap(App).catch(err => console.error(err)); + * ``` */ export interface OnChanges { onChanges(changes: StringMap); } /** - * Notify a directive when it has been checked the first time. + * Implement this interface to execute custom initialization logic after your directive's + * data-bound properties have been initialized. * - * `onInit` is called right after the directive's bindings have been checked for the first time, - * and before any of its children's bindings have been checked. + * `onInit` is called right after the directive's data-bound properties have been checked for the + * first time, and before any of its children have been checked. It is invoked only once when the + * directive is instantiated. * - * It is invoked only once. + * ### Example ([live example](http://plnkr.co/edit/1MBypRryXd64v4pV03Yn?p=preview)) * - * ## Example + * ```typescript + * @Component({selector: 'my-cmp'}) + * @View({template: `

my-component

`}) + * class MyComponent implements OnInit, OnDestroy { + * onInit() { + * console.log('onInit'); + * } * - * ``` - * @Component(...) - * class MyComponent implements OnInit { - * onInit(): void { + * onDestroy() { + * console.log('onDestroy'); * } * } + * + * @Component({selector: 'app'}) + * @View({ + * template: ` + * + * `, + * directives: [MyComponent, NgIf] + * }) + * export class App { + * hasChild = true; + * } + * + * bootstrap(App).catch(err => console.error(err)); * ``` */ export interface OnInit { onInit(); } /** - * Overrides the default change detection. + * Implement this interface to override the default change detection algorithm for your directive. * - * `doCheck()` gets called to check the changes in the directives instead of the default - * change detection mechanism. + * `doCheck` gets called to check the changes in the directives instead of the default algorithm. * - * It is invoked every time the change detection is triggered. + * The default change detection algorithm looks for differences by comparing bound-property values + * by reference across change detection runs. When `DoCheck` is implemented, the default algorithm + * is disabled and `doCheck` is responsible for checking for changes. * - * ## Example + * Implementing this interface allows improving performance by using insights about the component, + * its implementation and data types of its properties. * - * ``` - * @Component(...) - * class MyComponent implements DoCheck { - * doCheck(): void { - * // Custom logic to detect changes + * Note that a directive should not implement both `DoCheck` and {@link OnChanges} at the same time. + * `onChanges` would not be called when a directive implements `DoCheck`. Reaction to the changes + * have to be handled from within the `doCheck` callback. + * + * Use {@link KeyValueDiffers} and {@link IterableDiffers} to add your custom check mechanisms. + * + * ### Example ([live demo](http://plnkr.co/edit/QpnIlF0CR2i5bcYbHEUJ?p=preview)) + * + * In the following example `doCheck` uses an {@link IterableDiffers} to detect the updates to the + * array `list`: + * + * ```typescript + * @Component({selector: 'custom-check'}) + * @View({ + * template: ` + *

Changes:

+ * `, + * directives: [NgFor] + * }) + * class CustomCheckComponent implements DoCheck { + * @Property() list: any[]; + * differ: any; + * logs = []; + * + * constructor(differs: IterableDiffers) { + * this.differ = differs.find([]).create(null); + * } + * + * doCheck() { + * var changes = this.differ.diff(this.list); + * + * if (changes) { + * changes.forEachAddedItem(r => this.logs.push('added ' + r.item)); + * changes.forEachRemovedItem(r => this.logs.push('removed ' + r.item)) + * } * } * } - * ``` + * + * @Component({selector: 'app'}) + * @View({ + * template: ` + * + * + * `, + * directives: [CustomCheckComponent] + * }) + * export class App { + * list = []; + * } + * ``` */ export interface DoCheck { doCheck(); } /** - * Notify a directive whenever a {@link ViewMetadata} that contains it is destroyed. + * Implement this interface to get notified when your directive is destroyed. * - * ## Example + * `onDestroy` callback is typically used for any custom cleanup that needs to occur when the + * instance is destroyed * - * ``` - * @Component(...) - * class MyComponent implements OnDestroy { - * onDestroy(): void { - * // invoked to notify directive of the containing view destruction. + * ### Example ([live example](http://plnkr.co/edit/1MBypRryXd64v4pV03Yn?p=preview)) + * + * ```typesript + * @Component({selector: 'my-cmp'}) + * @View({template: `

my-component

`}) + * class MyComponent implements OnInit, OnDestroy { + * onInit() { + * console.log('onInit'); + * } + * + * onDestroy() { + * console.log('onDestroy'); * } * } - * ``` + * + * @Component({selector: 'app'}) + * @View({ + * template: ` + * + * `, + * directives: [MyComponent, NgIf] + * }) + * export class App { + * hasChild = true; + * } + * + * bootstrap(App).catch(err => console.error(err)); + * * ``` */ export interface OnDestroy { onDestroy(); } /** - * Notify a directive when the bindings of all its content children have been checked the first - * time (whether they have changed or not). + * Implement this interface to get notified when your directive's content has been fully + * initialized. * - * ## Example + * ### Example ([live demo](http://plnkr.co/edit/plamXUpsLQbIXpViZhUO?p=preview)) * - * ``` - * @Component(...) - * class MyComponent implements AfterContentInit { - * afterContentInit(): void { + * ```typescript + * @Component({selector: 'child-cmp'}) + * @View({template: `{{where}} child`}) + * class ChildComponent { + * @Property() where: string; + * } + * + * @Component({selector: 'parent-cmp'}) + * @View({template: ``}) + * class ParentComponent implements AfterContentInit { + * @ContentChild(ChildComponent) contentChild: ChildComponent; + * + * constructor() { + * // contentChild is not initialized yet + * console.log(this.getMessage(this.contentChild)); + * } + * + * afterContentInit() { + * // contentChild is updated after the content has been checked + * console.log('AfterContentInit: ' + this.getMessage(this.contentChild)); + * } + * + * private getMessage(cmp: ChildComponent): string { + * return cmp ? cmp.where + ' child' : 'no child'; * } * } - * ``` + * + * @Component({selector: 'app'}) + * @View({ + * template: ` + * + * + * `, + * directives: [ParentComponent, ChildComponent] + * }) + * export class App { + * } + * + * bootstrap(App).catch(err => console.error(err)); + * ``` */ export interface AfterContentInit { afterContentInit(); } /** - * Notify a directive when the bindings of all its content children have been checked (whether - * they have changed or not). + * Implement this interface to get notified after every check of your directive's content. * - * ## Example + * ### Example ([live demo](http://plnkr.co/edit/tGdrytNEKQnecIPkD7NU?p=preview)) * - * ``` - * @Component(...) - * class MyComponent implements AfterContentChecked { - * afterContentChecked(): void { + * ```typescript + * @Component({selector: 'child-cmp'}) + * @View({template: `{{where}} child`}) + * class ChildComponent { + * @Property() where: string; + * } + * + * @Component({selector: 'parent-cmp'}) + * @View({template: ``}) + * class ParentComponent implements AfterContentChecked { + * @ContentChild(ChildComponent) contentChild: ChildComponent; + * + * constructor() { + * // contentChild is not initialized yet + * console.log(this.getMessage(this.contentChild)); + * } + * + * afterContentChecked() { + * // contentChild is updated after the content has been checked + * console.log('AfterContentChecked: ' + this.getMessage(this.contentChild)); + * } + * + * private getMessage(cmp: ChildComponent): string { + * return cmp ? cmp.where + ' child' : 'no child'; * } * } - * ``` + * + * @Component({selector: 'app'}) + * @View({ + * template: ` + * + * + * + * `, + * directives: [NgIf, ParentComponent, ChildComponent] + * }) + * export class App { + * hasContent = true; + * } + * + * bootstrap(App).catch(err => console.error(err)); + * ``` */ export interface AfterContentChecked { afterContentChecked(); } /** - * Notify a directive when the bindings of all its view children have been checked the first time - * (whether they have changed or not). + * Implement this interface to get notified when your component's view has been fully initialized. * - * ## Example + * ### Example ([live demo](http://plnkr.co/edit/LhTKVMEM0fkJgyp4CI1W?p=preview)) * - * ``` - * @Component(...) - * class MyComponent implements AfterViewInit { - * afterViewInit(): void { + * ```typescript + * @Component({selector: 'child-cmp'}) + * @View({template: `{{where}} child`}) + * class ChildComponent { + * @Property() where: string; + * } + * + * @Component({selector: 'parent-cmp'}) + * @View({ + * template: ``, + * directives: [ChildComponent] + * }) + * class ParentComponent implements AfterViewInit { + * @ViewChild(ChildComponent) viewChild: ChildComponent; + * + * constructor() { + * // viewChild is not initialized yet + * console.log(this.getMessage(this.viewChild)); + * } + * + * afterViewInit() { + * // viewChild is updated after the view has been initialized + * console.log('afterViewInit: ' + this.getMessage(this.viewChild)); + * } + * + * private getMessage(cmp: ChildComponent): string { + * return cmp ? cmp.where + ' child' : 'no child'; * } * } - * ``` + * + * @Component({selector: 'app'}) + * @View({ + * template: ``, + * directives: [ParentComponent] + * }) + * export class App { + * } + * + * bootstrap(App).catch(err => console.error(err)); + * ``` */ export interface AfterViewInit { afterViewInit(); } /** - * Notify a directive when the bindings of all its view children have been checked (whether they - * have changed or not). + * Implement this interface to get notified after every check of your component's view. * - * ## Example + * ### Example ([live demo](http://plnkr.co/edit/0qDGHcPQkc25CXhTNzKU?p=preview)) * - * ``` - * @Component(...) - * class MyComponent implements AfterViewChecked { - * afterViewChecked(): void { + * ```typescript + * @Component({selector: 'child-cmp'}) + * @View({template: `{{where}} child`}) + * class ChildComponent { + * @Property() where: string; + * } + * + * @Component({selector: 'parent-cmp'}) + * @View({ + * template: ` + * + * `, + * directives: [NgIf, ChildComponent] + * }) + * class ParentComponent implements AfterViewChecked { + * @ViewChild(ChildComponent) viewChild: ChildComponent; + * showView = true; + * + * constructor() { + * // viewChild is not initialized yet + * console.log(this.getMessage(this.viewChild)); + * } + * + * afterViewChecked() { + * // viewChild is updated after the view has been checked + * console.log('AfterViewChecked: ' + this.getMessage(this.viewChild)); + * } + * + * private getMessage(cmp: ChildComponent): string { + * return cmp ? cmp.where + ' child' : 'no child'; * } * } - * ``` + * + * @Component({selector: 'app'}) + * @View({ + * template: ``, + * directives: [ParentComponent] + * }) + * export class App { + * } + * + * bootstrap(App).catch(err => console.error(err)); + * ``` */ export interface AfterViewChecked { afterViewChecked(); }