From f1ab3942187b52effeb74aac9c5f242e94f812ca Mon Sep 17 00:00:00 2001 From: Judy Bogart Date: Mon, 2 Jul 2018 12:06:52 -0700 Subject: [PATCH] docs: add api doc to commonly queried elements --- aio/content/guide/ngmodule-api.md | 11 +- .../change_detection/change_detector_ref.ts | 194 +++++--------- .../core/src/change_detection/constants.ts | 41 +-- packages/core/src/di/metadata.ts | 67 +++-- packages/core/src/event_emitter.ts | 38 ++- packages/core/src/metadata/di.ts | 9 +- packages/core/src/metadata/directives.ts | 212 +++------------ packages/core/src/metadata/lifecycle_hooks.ts | 245 ++++++++++++------ packages/core/src/metadata/ng_module.ts | 81 +++++- packages/core/src/render/api.ts | 191 +++++++++++++- .../core/ts/change_detect/change-detection.ts | 96 +++++++ 11 files changed, 712 insertions(+), 473 deletions(-) create mode 100644 packages/examples/core/ts/change_detect/change-detection.ts diff --git a/aio/content/guide/ngmodule-api.md b/aio/content/guide/ngmodule-api.md index e661cad113..5e11305445 100644 --- a/aio/content/guide/ngmodule-api.md +++ b/aio/content/guide/ngmodule-api.md @@ -12,8 +12,8 @@ A basic understanding of the following concepts: At a high level, NgModules are a way to organize Angular apps and they accomplish this through the metadata in the `@NgModule` -decorator. The metadata falls -into three categories: +decorator. +The metadata falls into three categories: * **Static:** Compiler configuration which tells the compiler about directive selectors and where in templates the directives should be applied through selector matching. This is configured via the `declarations` array. * **Runtime:** Injector configuration via the `providers` array. @@ -75,9 +75,8 @@ The following table summarizes the `@NgModule` metadata properties. Components, directives, and pipes must belong to _exactly_ one module. - The compiler emits an error if you try to declare the same class in more than one module. - - Don't re-declare a class imported from another module. + The compiler emits an error if you try to declare the same class in more than one module. Be careful not to re-declare a class that is imported + directly or indirectly from another module. @@ -108,7 +107,7 @@ The following table summarizes the `@NgModule` metadata properties. Components in external modules continue to receive the instance provided by their injectors. - For more information on injector hierarchy and scoping, see [Providers](guide/providers). + For more information on injector hierarchy and scoping, see [Providers](guide/providers) and the [DI Guide](guide/dependency-injection). diff --git a/packages/core/src/change_detection/change_detector_ref.ts b/packages/core/src/change_detection/change_detector_ref.ts index 2c50ff96aa..ffe982f003 100644 --- a/packages/core/src/change_detection/change_detector_ref.ts +++ b/packages/core/src/change_detection/change_detector_ref.ts @@ -6,179 +6,101 @@ * found in the LICENSE file at https://angular.io/license */ +/** + * Base class for Angular Views, provides change detection functionality. + * A change-detection tree collects all views that are to be checked for changes. + * Use the methods to add and remove views from the tree, initiate change-detection, + * and exlicitly mark views as _dirty_, meaning that they have changed and need to be rerendered. + * + * @usageNotes + * + * The following examples demonstrate how to modify default change-detection behavior + * to perform explicit detection when needed. + * + * ### Use `markForCheck()` with `checkOnce` strategy + * + * The following example sets the `OnPush` change-detection strategy for a component + * (`checkOnce`, rather than the default `checkAlways`), then forces a second check + * after an interval. See [live demo](http://plnkr.co/edit/GC512b?p=preview). + * + * + * + * ### Detach change detector to limit how often check occurs + * + * The following example defines a component with a large list of read-only data + * that is expected to change constantly, many times per second. + * To improve performance, we want to check and update the list + * less often than the changes actually occur. To do that, we detach + * the component's change detector and perform an explicit local check every five seconds. + * + * + * + * + * ### Reattaching a detached component + * + * The following example creates a component displaying live data. + * The component detaches its change detector from the main change detector tree + * when the `live` property is set to false, and reattaches it when the property + * becomes true. + * + * + * + */ export abstract class ChangeDetectorRef { /** - * Marks a view and all of its ancestors dirty. + * When a view uses the {@link ChangeDetectionStrategy#OnPush OnPush} (checkOnce) + * change detection strategy, explicitly marks the view as changed so that + * it can be checked again. * - * This can be used to ensure an {@link ChangeDetectionStrategy#OnPush OnPush} component is - * checked when it needs to be re-rendered but the two normal triggers haven't marked it - * dirty (i.e. inputs haven't changed and events haven't fired in the view). + * Components are normally marked as dirty (in need of rerendering) when inputs + * have changed or events have fired in the view. Call this method to ensure that + * a component is checked even if these triggers have not occured. * * * - * @usageNotes - * ### Example - * - * ```typescript - * @Component({ - * selector: 'my-app', - * template: `Number of ticks: {{numberOfTicks}}` - * changeDetection: ChangeDetectionStrategy.OnPush, - * }) - * class AppComponent { - * numberOfTicks = 0; - * - * constructor(private ref: ChangeDetectorRef) { - * setInterval(() => { - * this.numberOfTicks++; - * // the following is required, otherwise the view will not be updated - * this.ref.markForCheck(); - * }, 1000); - * } - * } - * ``` */ abstract markForCheck(): void; /** - * Detaches the view from the change detection tree. + * Detaches this view from the change-detection tree. + * A detached view is not checked until it is reattached. + * Use in combination with `detectChanges()` to implement local change detection checks. * - * Detached views will not be checked during change detection runs until they are - * re-attached, even if they are dirty. `detach` can be used in combination with - * {@link ChangeDetectorRef#detectChanges detectChanges} to implement local change - * detection checks. + * Detached views are not checked during change detection runs until they are + * re-attached, even if they are marked as dirty. * * * * - * @usageNotes - * ### Example - * - * The following example defines a component with a large list of readonly data. - * Imagine the data changes constantly, many times per second. For performance reasons, - * we want to check and update the list every five seconds. We can do that by detaching - * the component's change detector and doing a local check every five seconds. - * - * ```typescript - * class DataProvider { - * // in a real application the returned data will be different every time - * get data() { - * return [1,2,3,4,5]; - * } - * } - * - * @Component({ - * selector: 'giant-list', - * template: ` - *
  • Data {{d}}
  • - * `, - * }) - * class GiantList { - * constructor(private ref: ChangeDetectorRef, private dataProvider: DataProvider) { - * ref.detach(); - * setInterval(() => { - * this.ref.detectChanges(); - * }, 5000); - * } - * } - * - * @Component({ - * selector: 'app', - * providers: [DataProvider], - * template: ` - * - * `, - * }) - * class App { - * } - * ``` */ abstract detach(): void; /** - * Checks the view and its children. - * - * This can also be used in combination with {@link ChangeDetectorRef#detach detach} to implement - * local change detection checks. + * Checks this view and its children. Use in combination with {@link ChangeDetectorRef#detach + * detach} + * to implement local change detection checks. * * * * - * @usageNotes - * - * Imagine, the data changes constantly, many times per second. For performance reasons, - * we want to check and update the list every five seconds. - * - * We can do that by detaching the component's change detector and doing a local change detection - * check every five seconds. - * - * See {@link ChangeDetectorRef#detach detach} for more information. */ abstract detectChanges(): void; /** * Checks the change detector and its children, and throws if any changes are detected. * - * This is used in development mode to verify that running change detection doesn't introduce + * Use in development mode to verify that running change detection doesn't introduce * other changes. */ abstract checkNoChanges(): void; /** - * Re-attaches the view to the change detection tree. - * - * This can be used to re-attach views that were previously detached from the tree - * using {@link ChangeDetectorRef#detach detach}. Views are attached to the tree by default. + * Re-attaches the previously detached view to the change detection tree. + * Views are attached to the tree by default. * * * - * @usageNotes - * ### Example - * - * The following example creates a component displaying `live` data. The component will detach - * its change detector from the main change detector tree when the component's live property - * is set to false. - * - * ```typescript - * class DataProvider { - * data = 1; - * - * constructor() { - * setInterval(() => { - * this.data = this.data * 2; - * }, 500); - * } - * } - * - * @Component({ - * selector: 'live-data', - * inputs: ['live'], - * template: 'Data: {{dataProvider.data}}' - * }) - * class LiveData { - * constructor(private ref: ChangeDetectorRef, private dataProvider: DataProvider) {} - * - * set live(value) { - * if (value) { - * this.ref.reattach(); - * } else { - * this.ref.detach(); - * } - * } - * } - * - * @Component({ - * selector: 'my-app', - * providers: [DataProvider], - * template: ` - * Live Update: - * - * `, - * }) - * class AppComponent { - * live = true; - * } - * ``` */ abstract reattach(): void; } diff --git a/packages/core/src/change_detection/constants.ts b/packages/core/src/change_detection/constants.ts index 6add5fc6b2..3713b0f5a5 100644 --- a/packages/core/src/change_detection/constants.ts +++ b/packages/core/src/change_detection/constants.ts @@ -8,63 +8,74 @@ /** - * Describes within the change detector which strategy will be used the next time change - * detection is triggered. + * The strategy that the default change detector uses to detect changes. + * When set, takes effect the next time change detection is triggered. * */ export enum ChangeDetectionStrategy { /** - * `OnPush` means that the change detector's mode will be initially set to `CheckOnce`. + * Use the `CheckOnce` strategy, meaning that automatic change detection is deactivated + * until reactivated by setting the strategy to `Default` (`CheckAlways`). + * Change detection can still be explictly invoked. */ OnPush = 0, /** - * `Default` means that the change detector's mode will be initially set to `CheckAlways`. + * Use the default `CheckAlways` strategy, in which change detection is automatic until + * explicitly deactivated. */ Default = 1, } /** - * Describes the status of the detector. + * Defines the possible states of the default change detector. + * @see `ChangeDetectorRef` */ export enum ChangeDetectorStatus { /** - * `CheckOnce` means that after calling detectChanges the mode of the change detector - * will become `Checked`. + * A state in which, after calling `detectChanges()`, the change detector + * state becomes `Checked`, and must be explicitly invoked or reactivated. */ CheckOnce, /** - * `Checked` means that the change detector should be skipped until its mode changes to - * `CheckOnce`. + * A state in which change detection is skipped until the change detector mode + * becomes `CheckOnce`. */ Checked, /** - * `CheckAlways` means that after calling detectChanges the mode of the change detector - * will remain `CheckAlways`. + * A state in which change detection continues automatically until explictly + * deactivated. */ CheckAlways, /** - * `Detached` means that the change detector sub tree is not a part of the main tree and + * A state in which a change detector sub tree is not a part of the main tree and * should be skipped. */ Detached, /** - * `Errored` means that the change detector encountered an error checking a binding + * Indicates that the change detector encountered an error checking a binding * or calling a directive lifecycle method and is now in an inconsistent state. Change - * detectors in this state will no longer detect changes. + * detectors in this state do not detect changes. */ Errored, /** - * `Destroyed` means that the change detector is destroyed. + * Indicates that the change detector has been destroyed. */ Destroyed, } +/** + * Reports whether a given strategy is currently the default for change detection. + * @param changeDetectionStrategy The strategy to check. + * @returns True if the given strategy is the current default, false otherwise. + * @see `ChangeDetectorStatus` + * @see `ChangeDetectorRef` + */ export function isDefaultChangeDetectionStrategy(changeDetectionStrategy: ChangeDetectionStrategy): boolean { return changeDetectionStrategy == null || diff --git a/packages/core/src/di/metadata.ts b/packages/core/src/di/metadata.ts index ac10a47402..8198c9d0ea 100644 --- a/packages/core/src/di/metadata.ts +++ b/packages/core/src/di/metadata.ts @@ -18,19 +18,19 @@ import {EMPTY_ARRAY} from '../view/util'; */ export interface InjectDecorator { /** - * A parameter decorator that specifies a dependency. + * A constructor parameter decorator that specifies a + * custom provider of a dependency. * - * For more details, see the ["Dependency Injection Guide"](guide/dependency-injection). + * @see ["Dependency Injection Guide"](guide/dependency-injection). * * @usageNotes - * ### Example + * The following example shows a class constructor that specifies a + * custom provider of a dependency using the parameter decorator. * * {@example core/di/ts/metadata_spec.ts region='Inject'} * - * When `@Inject()` is not present, `Injector` will use the type annotation of the - * parameter. - * - * ### Example + * When `@Inject()` is not present, the `Injector` uses the type annotation of the + * parameter as the provider. * * {@example core/di/ts/metadata_spec.ts region='InjectWithoutDecorator'} */ @@ -41,7 +41,12 @@ export interface InjectDecorator { /** * Type of the Inject metadata. */ -export interface Inject { token: any; } +export interface Inject { + /** + * Injector token that maps to the dependency to be injected. + */ + token: any; +} /** * Inject decorator and metadata. @@ -56,15 +61,14 @@ export const Inject: InjectDecorator = makeParamDecorator('Inject', (token: any) */ export interface OptionalDecorator { /** - * A parameter metadata that marks a dependency as optional. - * `Injector` provides `null` if the dependency is not found. + * A constructor parameter decorator that marks a dependency as optional. * - * For more details, see the ["Dependency Injection Guide"](guide/dependency-injection). - * - * @usageNotes - * ### Example + * The DI framework provides null if the dependency is not found. + * For example, the following code allows the possibility of a null result: * * {@example core/di/ts/metadata_spec.ts region='Optional'} + * + * @see ["Dependency Injection Guide"](guide/dependency-injection). */ (): any; new (): Optional; @@ -87,14 +91,18 @@ export const Optional: OptionalDecorator = makeParamDecorator('Optional'); */ export interface SelfDecorator { /** - * Specifies that an `Injector` should retrieve a dependency only from itself. + * A constructor parameter decorator that tells the DI framework + * to retrieve a dependency only from the local injector. * - * For more details, see the ["Dependency Injection Guide"](guide/dependency-injection). - * - * @usageNotes - * ### Example + * In the following example, the dependency can be resolved + * by the local injector when instantiating the class itself, but not + * when instantiating a child. * * {@example core/di/ts/metadata_spec.ts region='Self'} + * + * @see ["Dependency Injection Guide"](guide/dependency-injection). + * + * */ (): any; new (): Self; @@ -118,14 +126,17 @@ export const Self: SelfDecorator = makeParamDecorator('Self'); */ export interface SkipSelfDecorator { /** - * Specifies that the dependency resolution should start from the parent injector. + * A constructor parameter decorator that tells the DI framework + * that dependency resolution should start from the parent injector. * - * For more details, see the ["Dependency Injection Guide"](guide/dependency-injection). - * - * @usageNotes - * ### Example + * In the following example, the dependency can be resolved when + * instantiating a child, but not when instantiating the class itself. * * {@example core/di/ts/metadata_spec.ts region='SkipSelf'} + * + * @see ["Dependency Injection Guide"](guide/dependency-injection). + * + * */ (): any; new (): SkipSelf; @@ -150,13 +161,13 @@ export const SkipSelf: SkipSelfDecorator = makeParamDecorator('SkipSelf'); */ export interface HostDecorator { /** - * Specifies that an injector should retrieve a dependency from any injector until + * A constructor parameter decorator that tells the DI framework + * to retrieve a dependency from any injector until * reaching the host element of the current component. * - * For more details, see the ["Dependency Injection Guide"](guide/dependency-injection). + * @see ["Dependency Injection Guide"](guide/dependency-injection). * - * @usageNotes - * ### Example + * @usageNotes * * {@example core/di/ts/metadata_spec.ts region='Host'} */ diff --git a/packages/core/src/event_emitter.ts b/packages/core/src/event_emitter.ts index 582bb61fb6..1e5368e88e 100644 --- a/packages/core/src/event_emitter.ts +++ b/packages/core/src/event_emitter.ts @@ -9,13 +9,15 @@ import {Subject, Subscription} from 'rxjs'; /** - * Use by directives and components to emit custom Events. + * Use in directives and components to emit custom events synchronously + * or asynchronously, and register handlers for those events by subscribing + * to an instance. * * @usageNotes - * ### Examples * - * In the following example, `Zippy` alternatively emits `open` and `close` events when its - * title gets clicked: + * In the following example, a component defines two output properties + * that create event emitters. When the title is clicked, the emitter + * emits an open or close event to toggle the current visibility state. * * ``` * @Component({ @@ -43,7 +45,7 @@ import {Subject, Subscription} from 'rxjs'; * } * ``` * - * The events payload can be accessed by the parameter `$event` on the components output event + * Access the event object with the `$event` argument passed to the output event * handler: * * ``` @@ -63,23 +65,37 @@ export class EventEmitter extends Subject { // we can't mark it as internal now because EventEmitter exported via @angular/core would not // contain this property making it incompatible with all the code that uses EventEmitter via // facades, which are local to the code and do not have this property stripped. - // tslint:disable-next-line - __isAsync: boolean; + /** + * Internal + */ + __isAsync: boolean; // tslint:disable-line /** - * Creates an instance of {@link EventEmitter}, which depending on `isAsync`, - * delivers events synchronously or asynchronously. + * Creates an instance of this class that can + * deliver events synchronously or asynchronously. + * + * @param isAsync When true, deliver events asynchronously. * - * @param isAsync By default, events are delivered synchronously (default value: `false`). - * Set to `true` for asynchronous event delivery. */ constructor(isAsync: boolean = false) { super(); this.__isAsync = isAsync; } + /** + * Emits an event containing a given value. + * @param value The value to emit. + */ emit(value?: T) { super.next(value); } + /** + * Registers handlers for events emitted by this instance. + * @param generatorOrNext When supplied, a custom handler for emitted events. + * @param error When supplied, a custom handler for an error notification + * from this emitter. + * @param complete When supplied, a custom handler for a completion + * notification from this emitter. + */ subscribe(generatorOrNext?: any, error?: any, complete?: any): any { let schedulerFn: (t: any) => any; let errorFn = (err: any): any => null; diff --git a/packages/core/src/metadata/di.ts b/packages/core/src/metadata/di.ts index d25a9a52fa..c568bbdf18 100644 --- a/packages/core/src/metadata/di.ts +++ b/packages/core/src/metadata/di.ts @@ -309,11 +309,10 @@ export const ViewChildren: ViewChildrenDecorator = makePropDecorator( export interface ViewChildDecorator { /** * @description - * Configures a view query. - * - * You can use ViewChild to get the first element or the directive matching the selector from the - * view DOM. If the view DOM changes, and a new child matches the selector, - * the property will be updated. + * Property decorator that configures a view query. + * The change detector looks for the first element or the directive matching the selector + * in the view DOM. If the view DOM changes, and a new child matches the selector, + * the property is updated. * * View queries are set before the `ngAfterViewInit` callback is called. * diff --git a/packages/core/src/metadata/directives.ts b/packages/core/src/metadata/directives.ts index 0784cef48b..e1e8a296f0 100644 --- a/packages/core/src/metadata/directives.ts +++ b/packages/core/src/metadata/directives.ts @@ -19,37 +19,18 @@ import {ViewEncapsulation} from './view'; */ export interface DirectiveDecorator { /** - * Marks a class as an Angular directive and collects directive configuration - * metadata. - * - * Directive decorator allows you to mark a class as an Angular directive and provide additional - * metadata that determines how the directive should be processed, instantiated and used at + * Marks a class as an Angular directive. You can define your own + * directives to attach custom behavior to elements in the DOM. + * The options provide configuration metadata that determines + * how the directive should be processed, instantiated and used at * runtime. * - * Directives allow you to attach behavior to elements in the DOM.. + * Directive classes, like component classes, can implement + * [life-cycle hoooks](guide/lifecycle-hooks) to influence their configuration and behavior. * - * A directive must belong to an NgModule in order for it to be usable - * by another directive, component, or application. To specify that a directive is a member of an - * NgModule, - * you should list it in the `declarations` field of that NgModule. - * - * In addition to the metadata configuration specified via the Directive decorator, - * directives can control their runtime behavior by implementing various Life-Cycle hooks. - * - * **Metadata Properties:** - * - * * **exportAs** - name under which the component instance is exported in a template. Can be - * given a single name or a comma-delimited list of names. - * * **host** - map of class property to host element bindings for events, properties and - * attributes - * * **inputs** - list of class property names to data-bind as component inputs - * * **outputs** - list of class property names that expose output events that others can - * subscribe to - * * **providers** - list of providers available to this component and its children - * * **queries** - configure queries that can be injected into the component - * * **selector** - css selector that identifies this component in a template * * @usageNotes + * To define a directive, mark the class with the decorator and provide metadata. * * ``` * import {Directive} from '@angular/core'; @@ -58,9 +39,27 @@ export interface DirectiveDecorator { * selector: 'my-directive', * }) * export class MyDirective { + * ... * } * ``` * + * ### Declaring directives + * + * Directives are [declarables](guide/glossary#declarable). + * Like component and pipes, they must be declared by an NgModule + * in order to be usable in an app. + * + * A directive must belong to exactly one NgModule. Do not re-declare + * a directive imported from another module. + * List the directive class in the `declarations` field of an NgModule. + * + * ``` + * declarations: [ + * AppComponent, + * MyDirective + * ], + * ``` + * * @Annotation */ (obj: Directive): TypeDecorator; @@ -75,10 +74,7 @@ export interface Directive { /** * The CSS selector that triggers the instantiation of a directive. * - * Angular only allows directives to trigger on CSS selectors that do not cross element - * boundaries. - * - * `selector` may be declared as one of the following: + * Declare as one of the following: * * - `element-name`: select by element name. * - `.class`: select by class name. @@ -87,12 +83,10 @@ export interface Directive { * - `:not(sub_selector)`: select only if the element does not match the `sub_selector`. * - `selector1, selector2`: select if either `selector1` or `selector2` matches. * - * @usageNotes - * ### Example - * - * Suppose we have a directive with an `input[type=text]` selector. - * - * And the following HTML: + * Angular only allows directives to trigger on CSS selectors that do not cross element + * boundaries. For example, consider a directive with an `input[type=text]` selector. + * For the following HTML, the directive is instantiated only on the + * `` element. * * ```html *
    @@ -101,8 +95,6 @@ export interface Directive { * * ``` * - * The directive would only be instantiated on the `` element. - * */ selector?: string; @@ -110,7 +102,6 @@ export interface Directive { * Enumerates the set of data-bound input properties for a directive * * Angular automatically updates input properties during change detection. - * * The `inputs` property defines a set of `directiveProperty` to `bindingProperty` * configuration: * @@ -118,8 +109,8 @@ export interface Directive { * - `bindingProperty` specifies the DOM property where the value is read from. * * When `bindingProperty` is not provided, it is assumed to be equal to `directiveProperty`. - * * @usageNotes + * * ### Example * * The following example creates a component with two data-bound properties. @@ -154,6 +145,7 @@ export interface Directive { * - `bindingProperty` specifies the DOM property the event handler is attached to. * * @usageNotes + * * ### Example * * ```typescript @@ -175,138 +167,8 @@ export interface Directive { outputs?: string[]; /** - * Specify the events, actions, properties and attributes related to the host element. - * - * @usageNotes - * The key corresponds to the name of the event, property or attribute on the host to - * bind. The value is formatted differently depending upon the type of the binding. - * - * ### Host Listeners - * - * Specifies which DOM events a directive listens to via a set of `(event)` to `method` - * key-value pairs: - * - * - `event`: the DOM event that the directive listens to. - * - `statement`: the statement to execute when the event occurs. - * If the evaluation of the statement returns `false`, then `preventDefault`is applied on the DOM - * event. - * - * To listen to global events, a target must be added to the event name. - * The target can be `window`, `document` or `body`. - * - * When writing a directive event binding, you can also refer to the $event local variable. - * - * The following example declares a directive that attaches a click listener to the button and - * counts clicks. - * - * ```typescript - * @Directive({ - * selector: 'button[counting]', - * host: { - * '(click)': 'onClick($event.target)' - * } - * }) - * class CountClicks { - * numberOfClicks = 0; - * - * onClick(btn) { - * console.log("button", btn, "number of clicks:", this.numberOfClicks++); - * } - * } - * - * @Component({ - * selector: 'app', - * template: `` - * }) - * class App {} - * ``` - * See [live demo](http://plnkr.co/edit/DlA5KU?p=preview) - * - * ### Host Property Bindings - * - * Specifies which DOM properties a directive updates. - * - * Angular automatically checks host property bindings during change detection. - * If a binding changes, it will update the host element of the directive. - * - * The following example creates a directive that sets the `valid` and `invalid` classes - * on the DOM element that has ngModel directive on it. - * - * ```typescript - * @Directive({ - * selector: '[ngModel]', - * host: { - * '[class.valid]': 'valid', - * '[class.invalid]': 'invalid' - * } - * }) - * class NgModelStatus { - * constructor(public control:NgModel) {} - * get valid { return this.control.valid; } - * get invalid { return this.control.invalid; } - * } - * - * @Component({ - * selector: 'app', - * template: `` - * }) - * class App { - * prop; - * } - * ``` - * See [live demo](http://plnkr.co/edit/gNg0ED?p=preview). - * - * ### Attributes - * - * Specifies static attributes that should be propagated to a host element. - * - * In this example using `my-button` directive (ex.: `
    `) on a host element - * (here: `
    ` ) will ensure that this element will get the "button" role. - * - * ```typescript - * @Directive({ - * selector: '[my-button]', - * host: { - * 'role': 'button' - * } - * }) - * class MyButton { - * } - * ``` - * Attaching the `my-button` directive to the host `
    ` element - * ensures that this element gets the "button" role. - * - * ```html - *
    - * ``` - * - * @usageNotes - * ### Simple Example - * - * The following simple example shows how a class is injected, - * using a provider specified in the directive metadata: - * - * ``` - * class Greeter { - * greet(name:string) { - * return 'Hello ' + name + '!'; - * } - * } - * - * @Directive({ - * selector: 'greet', - * providers: [ - * Greeter - * ] - * }) - * class HelloWorld { - * greeter:Greeter; - * - * constructor(greeter:Greeter) { - * this.greeter = greeter; - * } - * } - * ``` + * A set of injection tokens that allow the DI system to + * provide a dependency to this directive or component. */ providers?: Provider[]; @@ -314,6 +176,7 @@ export interface Directive { * Defines the name that can be used in the template to assign this directive to a variable. * * @usageNotes + * * ### Simple Example * * ``` @@ -330,7 +193,6 @@ export interface Directive { * }) * class MainComponent { * } - * * ``` */ exportAs?: string; @@ -456,7 +318,9 @@ export interface Directive { host?: {[key: string]: string}; /** - * See the `Component` decorator. + * Configures the [injector](guide/glossary#injector) of this + * directive or component with a [token](guide/glossary#di-token) + * that maps to a [provider](guide/glossary#provider) of a dependency. */ providers?: Provider[]; diff --git a/packages/core/src/metadata/lifecycle_hooks.ts b/packages/core/src/metadata/lifecycle_hooks.ts index 426752f28f..d28f62eb11 100644 --- a/packages/core/src/metadata/lifecycle_hooks.ts +++ b/packages/core/src/metadata/lifecycle_hooks.ts @@ -10,138 +10,225 @@ import {SimpleChange} from '../change_detection/change_detection_util'; /** - * A `changes` object whose keys are property names and - * values are instances of {@link SimpleChange}. See {@link OnChanges} + * Defines an object that associates properties with + * instances of `SimpleChange`. + * + * @see `OnChanges` * */ export interface SimpleChanges { [propName: string]: SimpleChange; } /** + * @description + * A lifecycle hook that is called when any data-bound property of a directive changes. + * Define an `ngOnChanges()` method to handle the changes. + * + * @see `DoCheck` + * @see `OnInit` + * @see [Lifecycle Hooks](guide/lifecycle-hooks#onchanges) guide + * * @usageNotes + * The following snippet shows how a component can implement this interface to + * define an on-changes handler for an input property. + * * {@example core/ts/metadata/lifecycle_hooks_spec.ts region='OnChanges'} * - * @description - * Lifecycle hook that is called when any data-bound property of a directive changes. - * - * `ngOnChanges` 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. - * The `changes` parameter contains the changed properties. - * - * See ["Lifecycle Hooks Guide"](guide/lifecycle-hooks#onchanges). - * - * */ -export interface OnChanges { ngOnChanges(changes: SimpleChanges): void; } +export interface OnChanges { + /** + * A callback method that is invoked immediately after the + * default change detector has checked data-bound properties + * if at least one has changed, and before the view and content + * children are checked. + * @param changes The changed properties. + */ + ngOnChanges(changes: SimpleChanges): void; +} /** + * @description + * A lifecycle hook that is called after Angular has initialized + * all data-bound properties of a directive. + * Define an `ngOnInit()` method to handle any additional initialization tasks. + * + * @see `AfterContentInit` + * @see [Lifecycle Hooks](guide/lifecycle-hooks#onchanges) guide + * * @usageNotes + * The following snippet shows how a component can implement this interface to + * define its own initialization method. + * * {@example core/ts/metadata/lifecycle_hooks_spec.ts region='OnInit'} * - * @description - * Lifecycle hook that is called after data-bound properties of a directive are - * initialized. - * - * `ngOnInit` 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. - * - * See ["Lifecycle Hooks Guide"](guide/lifecycle-hooks). - * * */ -export interface OnInit { ngOnInit(): void; } +export interface OnInit { + /** + * A callback method that is invoked immediately after the + * default change detector has checked the directive's + * data-bound properties for the first time, + * and before any of the view or content children have been checked. + * It is invoked only once when the directive is instantiated. + */ + ngOnInit(): void; +} /** + * A lifecycle hook that invokes a custom change-detection function for a directive, + * in addition to the check performed by the default change-detector. + * + * The default change-detection algorithm looks for differences by comparing + * bound-property values by reference across change detection runs. You can use this + * hook to check for and respond to changes by some other means. + * + * When the default change detector detects changes, it invokes `ngOnChanges()` if supplied, + * regardless of whether you perform additional change detection. + * Typically, you should not use both `DoCheck` and `OnChanges` to respond to + * changes on the same input. + * + * @see `OnChanges` + * @see [Lifecycle Hooks](guide/lifecycle-hooks#onchanges) guide + * * @usageNotes + * The following snippet shows how a component can implement this interface + * to invoke it own change-detection cycle. + * * {@example core/ts/metadata/lifecycle_hooks_spec.ts region='DoCheck'} * - * @description - * Lifecycle hook that is called when Angular dirty checks a directive. - * - * `ngDoCheck` gets called to check the changes in the directives in addition to the default - * algorithm. The default change detection algorithm looks for differences by comparing - * bound-property values by reference across change detection runs. - * - * Note that a directive typically should not use both `DoCheck` and {@link OnChanges} to respond to - * changes on the same input, as `ngOnChanges` will continue to be called when the default change - * detector detects changes. - * - * See {@link KeyValueDiffers} and {@link IterableDiffers} for implementing custom dirty checking - * for collections. - * - * See ["Lifecycle Hooks Guide"](guide/lifecycle-hooks#docheck). - * - * */ -export interface DoCheck { ngDoCheck(): void; } +export interface DoCheck { + /** + * A callback method that performs change-detection, invoked + * after the default change-detector runs. + * @see `KeyValueDiffers` and `IterableDiffers` for implementing + * custom change checking for collections. + * + */ + ngDoCheck(): void; +} /** + * A lifecycle hook that is called when a directive, pipe, or service is destroyed. + * Use for any custom cleanup that needs to occur when the + * instance is destroyed. + * @see [Lifecycle Hooks](guide/lifecycle-hooks#onchanges) guide + * * @usageNotes + * The following snippet shows how a component can implement this interface + * to define it own custom clean-up method. + * * {@example core/ts/metadata/lifecycle_hooks_spec.ts region='OnDestroy'} * - * @description - * Lifecycle hook that is called when a directive, pipe or service is destroyed. - * - * `ngOnDestroy` callback is typically used for any custom cleanup that needs to occur when the - * instance is destroyed. - * - * See ["Lifecycle Hooks Guide"](guide/lifecycle-hooks). - * - * */ -export interface OnDestroy { ngOnDestroy(): void; } +export interface OnDestroy { + /** + * A callback method that performs custom clean-up, invoked immediately + * after a directive, pipe, or service instance is destroyed. + */ + ngOnDestroy(): void; +} /** + * @description + * A lifecycle hook that is called after Angular has fully initialized + * all content of a directive. + * Define an `ngAfterContentInit()` method to handle any additional initialization tasks. + * + * @see `OnInit` + * @see `AfterViewInit` + * @see [Lifecycle Hooks](guide/lifecycle-hooks#onchanges) guide * * @usageNotes + * The following snippet shows how a component can implement this interface to + * define its own content initialization method. + * * {@example core/ts/metadata/lifecycle_hooks_spec.ts region='AfterContentInit'} * - * @description - * Lifecycle hook that is called after a directive's content has been fully - * initialized. - * - * See ["Lifecycle Hooks Guide"](guide/lifecycle-hooks#aftercontent). - * * */ -export interface AfterContentInit { ngAfterContentInit(): void; } +export interface AfterContentInit { + /** + * A callback method that is invoked immediately after + * Angular has completed initialization of all of the directive's + * content. + * It is invoked only once when the directive is instantiated. + */ + ngAfterContentInit(): void; +} /** + * @description + * A lifecycle hook that is called after the default change detector has + * completed checking all content of a directive. + * + * @see `AfterViewChecked` + * @see [Lifecycle Hooks](guide/lifecycle-hooks#onchanges) guide + * * @usageNotes + * The following snippet shows how a component can implement this interface to + * define its own after-check functionality. + * * {@example core/ts/metadata/lifecycle_hooks_spec.ts region='AfterContentChecked'} * - * @description - * Lifecycle hook that is called after every check of a directive's content. - * - * See ["Lifecycle Hooks Guide"](guide/lifecycle-hooks#aftercontent). - * * */ -export interface AfterContentChecked { ngAfterContentChecked(): void; } +export interface AfterContentChecked { + /** + * A callback method that is invoked immediately after the + * default change detector has completed checking all of the directive's + * content. + */ + ngAfterContentChecked(): void; +} /** + * @description + * A lifecycle hook that is called after Angular has fully initialized + * a component's view. + * Define an `ngAfterViewInit()` method to handle any additional initialization tasks. + * + * @see `OnInit` + * @see `AfterContentInit` + * @see [Lifecycle Hooks](guide/lifecycle-hooks#onchanges) guide + * * @usageNotes + * The following snippet shows how a component can implement this interface to + * define its own view initialization method. + * * {@example core/ts/metadata/lifecycle_hooks_spec.ts region='AfterViewInit'} * - * @description - * Lifecycle hook that is called after a component's view has been fully - * initialized. - * - * See ["Lifecycle Hooks Guide"](guide/lifecycle-hooks#afterview). - * * */ -export interface AfterViewInit { ngAfterViewInit(): void; } +export interface AfterViewInit { + /** + * A callback method that is invoked immediately after + * Angular has completed initialization of a component's view. + * It is invoked only once when the view is instantiated. + * + */ + ngAfterViewInit(): void; +} /** + * @description + * A lifecycle hook that is called after the default change detector has + * completed checking a component's view for changes. + * + * @see `AfterContentChecked` + * @see [Lifecycle Hooks](guide/lifecycle-hooks#onchanges) guide + * * @usageNotes + * The following snippet shows how a component can implement this interface to + * define its own after-check functionality. + * * {@example core/ts/metadata/lifecycle_hooks_spec.ts region='AfterViewChecked'} * - * @description - * Lifecycle hook that is called after every check of a component's view. - * - * See ["Lifecycle Hooks Guide"](guide/lifecycle-hooks#afterview). - * - * */ -export interface AfterViewChecked { ngAfterViewChecked(): void; } +export interface AfterViewChecked { + /** + * A callback method that is invoked immediately after the + * default change detector has completed one change-check cycle + * for a component's view. + */ + ngAfterViewChecked(): void; +} diff --git a/packages/core/src/metadata/ng_module.ts b/packages/core/src/metadata/ng_module.ts index 78de8a4347..6e3ce00e83 100644 --- a/packages/core/src/metadata/ng_module.ts +++ b/packages/core/src/metadata/ng_module.ts @@ -136,9 +136,26 @@ export interface NgModule { /** * The set of injectable objects that are available in the injector * of this module. + * + * @see [Dependency Injection guide](guide/dependency-injection) + * @see [NgModule guide](guide/providers) * * @usageNotes * + * Dependencies whose providers are listed here become available for injection + * into any component, directive, pipe or service that is a child of this injector. + * The NgModule used for bootstrapping uses the root injector, and can provide dependencies + * to any part of the app. + * + * A lazy-loaded module has its own injector, typically a child of the app root injector. + * Lazy-loaded services are scoped to the lazy-loaded module's injector. + * If a lazy-loaded module also provides the `UserService`, any component created + * within that module's context (such as by router navigation) gets the local instance + * of the service, not the instance in the root injector. + * Components in external modules continue to receive the instance provided by their injectors. + * + * ### Example + * * The following example defines a class that is injected in * the HelloWorld NgModule: * @@ -166,10 +183,20 @@ export interface NgModule { providers?: Provider[]; /** - * The set of directives and pipes that belong to this module. + * The set of components, directives, and pipes ([declarables](guide/glossary#declarable)) + * that belong to this module. * * @usageNotes * + * The set of selectors that are available to a template include those declared here, and + * those that are exported from imported NgModules. + * + * Declarables must belong to exactly one module. + * The compiler emits an error if you try to declare the same class in more than one module. + * Be careful not to declare a class that is imported from another module. + * + * ### Example + * * The following example allows the CommonModule to use the `NgFor` * directive. * @@ -184,13 +211,19 @@ export interface NgModule { declarations?: Array|any[]>; /** - * The set of NgModules, with or without providers, - * whose exported directives/pipes + * The set of NgModules whose exported directives and pipes * are available to templates in this module. * * @usageNotes * - * The following example allows MainModule to use CommonModule: + * A template can exported declarables from any + * imported module, including those that are imported indirectly. + * For example, `CommonModule` imports `BrowserModule`, make the + * `BrowserModule` exports available wherever `CommonModule` is imported. + * + * ### Example + * + * The following example allows MainModule to use `CommonModule`: * * ```javascript * @NgModule({ @@ -199,17 +232,31 @@ export interface NgModule { * class MainModule { * } * ``` - * @see {@link ModuleWithProviders} + * */ imports?: Array|ModuleWithProviders|any[]>; /** - * The set of directives, pipe, and NgModules that can be used - * within the template of any component that is part of an - * NgModule that imports this NgModule. + * The set of components, directives, and pipes declared in this + * NgModule that can be used in the template of any component that is part of an + * NgModule that imports this NgModule. Exported declarations are the module's public API. * * @usageNotes * + * Declarations are private by default. If this module does not export UserComponent, + * then only the components within this module can use UserComponent. + * + * Importing a module does not automatically re-export the imported module's imports. + * Module 'B' can't use `ngIf` just because it imported module 'A' which imported `CommonModule`. + * Module 'B' must import `CommonModule` itself. + * + * A module can list another module among its exports, in which case all of that module's + * public declaration are exported. Re-export makes module transitivity explicit. + * If Module 'A' re-exports `CommonModule` and Module 'B' imports Module 'A', + * then Module 'B' components can use `ngIf` even though 'B' itself did not import `CommonModule`. + * + * ### Example + * * The following example exports the `NgFor` directive from CommonModule. * * ```javascript @@ -223,9 +270,18 @@ export interface NgModule { exports?: Array|any[]>; /** - * The set of components to compile when this NgModule is defined. + * The set of components to compile when this NgModule is defined, + * so that they can be dynamically loaded into the view. + * * For each component listed here, Angular creates a `ComponentFactory` * and stores it in the `ComponentFactoryResolver`. + * + * Angular automatically adds components in the module's bootstrap + * and route definitions into the `entryComponents` list. Use this + * option to add components that are bootstrapped + * using one of the imperative techniques, such as `ViewComponentRef.createComponent()`. + * + * @see [Entry Components](guide/entry-components) */ entryComponents?: Array|any[]>; @@ -285,5 +341,12 @@ export const NgModule: NgModuleDecorator = makeDecorator( /** * Decorator that marks the following class as an NgModule, and supplies * configuration metadata for it. + * + * * The `declarations` and `entryComponents` options configure the compiler + * with information about what belongs to the NgModule. + * * The `providers` options configures the NgModule's injector to provide + * dependencies the NgModule members. + * * The `import` and `export` options bring in members from other modules, and make + * this module's members available to others. */ (type: Type, meta: NgModule) => (R3_COMPILE_NGMODULE || preR3NgModuleCompile)(type, meta)); diff --git a/packages/core/src/render/api.ts b/packages/core/src/render/api.ts index ac80fd769c..b3b281bb3f 100644 --- a/packages/core/src/render/api.ts +++ b/packages/core/src/render/api.ts @@ -113,78 +113,249 @@ export abstract class RootRenderer { } /** - * @experimental + * Used by `RendererFactory2` to associate custom rendering data and styles + * with a rendering implementation. + * @experimental */ export interface RendererType2 { + /** + * A unique identifying string for the new renderer, used when creating + * unique styles for encapsulation. + */ id: string; + /** + * The view encapsulation type, which determines how styles are applied to + * DOM elements. One of + * - `Emulated` (default): Emulate native scoping of styles. + * - `Native`: Use the native encapsulation mechanism of the renderer. + * - `ShadowDoc`: Use modern [Shadow + * DOM](https://w3c.github.io/webcomponents/spec/shadow/) and + * create a ShadowRoot for component's host element. + * - `None`: Do not provide any template or style encapsulation. + */ encapsulation: ViewEncapsulation; + /** + * Defines CSS styles to be stored on a renderer instance. + */ styles: (string|any[])[]; + /** + * Defines arbitrary developer-defined data to be stored on a renderer instance. + * This is useful for renderers that delegate to other renderers. + */ data: {[kind: string]: any}; } /** + * Creates and initializes a custom renderer that implements the `Renderer2` base class. + * * @experimental */ export abstract class RendererFactory2 { + /** + * Implements a custom renderer for a host DOM element. + * @param hostElement The element to render. + * @param type The base class to implement. + * @returns The new custom renderer instance. + */ abstract createRenderer(hostElement: any, type: RendererType2|null): Renderer2; + /** + * A callback invoked when rendering has begun. + */ abstract begin?(): void; + /** + * A callback invoked when rendering has completed. + */ abstract end?(): void; + /** + * Use with animations test-only mode. Notifies the test when rendering has completed. + * @returns The asynchronous result of the developer-defined function. + */ abstract whenRenderingDone?(): Promise; } /** + * Flags for renderer-specific style modifiers. * @experimental */ export enum RendererStyleFlags2 { + /** + * Marks a style as important. + */ Important = 1 << 0, + /** + * Marks a style as using dash case naming (this-is-dash-case). + */ DashCase = 1 << 1 } /** + * Extend this base class to implement custom rendering. By default, Angular + * renders a template into DOM. You can use custom rendering to intercept + * rendering calls, or to render to something other than DOM. + * + * Create your custom renderer using `RendererFactory2`. + * + * Use a custom renderer to bypass Angular's templating and make custom UI changes that can't be + * expressed declaratively. + * For example if you need to set a property or an attribute whose name is + * not statically known, use the `setElementProperty()` or + * `setElementAttribute()` method. + * * @experimental */ export abstract class Renderer2 { /** - * This field can be used to store arbitrary data on this renderer instance. + * Implement this callback to store arbitrary developer-defined data on a renderer instance, + * as an object containing key-value pairs. * This is useful for renderers that delegate to other renderers. */ abstract get data(): {[key: string]: any}; + /** + * Implement this callback to destroy the renderer or the host element. + */ abstract destroy(): void; + /** + * Implement this callback to create an instance of the host element. + * @param name An identifying name for the new element, unique within the namespace. + * @param namespace The namespace for the new element. + * @returns The new element. + */ abstract createElement(name: string, namespace?: string|null): any; + /** + * Implement this callback to add a comment to the DOM of the host element. + * @param value The comment text. + * @returns The modified element. + */ abstract createComment(value: string): any; + + /** + * Implement this callback to add text to the DOM of the host element. + * @param value The text string. + * @returns The modified element. + */ abstract createText(value: string): any; /** - * This property is allowed to be null / undefined, - * in which case the view engine won't call it. + * If null or undefined, the view engine won't call it. * This is used as a performance optimization for production mode. */ // TODO(issue/24571): remove '!'. destroyNode !: ((node: any) => void) | null; + /** + * Appends a child to a given parent node in the host element DOM. + * @param parent The parent node. + * @param newChild The new child node. + */ abstract appendChild(parent: any, newChild: any): void; + /** + * Implement this callback to insert a child node at a given position in a parent node + * in the host element DOM. + * @param parent The parent node. + * @param newChild The new child nodes. + * @param refChild The existing child node that should precede the new node. + */ abstract insertBefore(parent: any, newChild: any, refChild: any): void; + /** + * Implement this callback to remove a child node from the host element's DOM. + * @param parent The parent node. + * @param oldChild The child node to remove. + */ abstract removeChild(parent: any, oldChild: any): void; + /** + * Implement this callback to get the root element of a DOM element. + * @param selectorOrNode The DOM element. + * @returns The root element. + */ abstract selectRootElement(selectorOrNode: string|any): any; /** - * Attention: On WebWorkers, this will always return a value, - * as we are asking for a result synchronously. I.e. - * the caller can't rely on checking whether this is null or not. + * Implement this callback to get the parent of a given node + * in the host element's DOM. + * @param node The child node to query. + * @returns The parent node, or null if there is no parent. + * For WebWorkers, always returns true. + * This is because the check is synchronous, + * and the caller can't rely on checking for null. */ abstract parentNode(node: any): any; /** - * Attention: On WebWorkers, this will always return a value, - * as we are asking for a result synchronously. I.e. - * the caller can't rely on checking whether this is null or not. + * Implement this callback to get the next sibling node of a given node + * in the host element's DOM. + * @returns The sibling node, or null if there is no sibling. + * For WebWorkers, always returns a value. + * This is because the check is synchronous, + * and the caller can't rely on checking for null. */ abstract nextSibling(node: any): any; + /** + * Implement this callback to set an attribute value for an element in the DOM. + * @param el The element. + * @param name The attribute name. + * @param value The new value. + * @param namespace The namespace. + */ abstract setAttribute(el: any, name: string, value: string, namespace?: string|null): void; + + /** + * Implement this callback to remove an attribute from an element in the DOM. + * @param el The element. + * @param name The attribute name. + * @param namespace The namespace. + */ abstract removeAttribute(el: any, name: string, namespace?: string|null): void; + /** + * Implement this callback to add a class to an element in the DOM. + * @param el The element. + * @param name The class name. + */ abstract addClass(el: any, name: string): void; + + /** + * Implement this callback to remove a class from an element in the DOM. + * @param el The element. + * @param name The class name. + */ abstract removeClass(el: any, name: string): void; + + /** + * Implement this callback to set a CSS style for an element in the DOM. + * @param el The element. + * @param style The name of the style. + * @param value The new value. + * @param flags Flags for style variations. No flags are set by default. + */ abstract setStyle(el: any, style: string, value: any, flags?: RendererStyleFlags2): void; + + /** + * Implement this callback to remove the value from a CSS style for an element in the DOM. + * @param el The element. + * @param style The name of the style. + * @param flags Flags for style variations to remove, if set. ??? + */ abstract removeStyle(el: any, style: string, flags?: RendererStyleFlags2): void; + + /** + * Implement this callback to set the value of a property of an element in the DOM. + * @param el The element. + * @param name The property name. + * @param value The new value. + */ abstract setProperty(el: any, name: string, value: any): void; + + /** + * Implement this callback to set the value of a node in the host element. + * @param node The node. + * @param value The new value. + */ abstract setValue(node: any, value: string): void; + + /** + * Implement this callback to start an event listener. + * @param target The context in which to listen for events. Can be + * the entire window or document, the body of the document, or a specific + * DOM element. + * @param eventName The event to listen for. + * @param callback A handler function to invoke when the event occurs. + */ abstract listen( target: 'window'|'document'|'body'|any, eventName: string, callback: (event: any) => boolean | void): () => void; diff --git a/packages/examples/core/ts/change_detect/change-detection.ts b/packages/examples/core/ts/change_detect/change-detection.ts new file mode 100644 index 0000000000..8124ab43de --- /dev/null +++ b/packages/examples/core/ts/change_detect/change-detection.ts @@ -0,0 +1,96 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ +/* tslint:disable:no-console */ +import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Directive} from '@angular/core'; + + +// #docregion mark-for-check +@Component({ + selector: 'my-app', + template: `Number of ticks: {{numberOfTicks}}`, + changeDetection: ChangeDetectionStrategy.OnPush, +}) + +class AppComponent { + numberOfTicks = 0; + + constructor(private ref: ChangeDetectorRef) { + setInterval(() => { + this.numberOfTicks++; + // require view to be updated + this.ref.markForCheck(); + }, 1000); + } +} +// #enddocregion mark-for-check + +// #docregion detach +class DataListProvider { + // in a real application the returned data will be different every time + get data() { return [1, 2, 3, 4, 5]; } +} + +@Component({ + selector: 'giant-list', + template: ` +
  • Data {{d}}
  • + `, +}) +class GiantList { + constructor(private ref: ChangeDetectorRef, private dataProvider: DataListProvider) { + ref.detach(); + setInterval(() => { this.ref.detectChanges(); }, 5000); + } +} + +@Component({ + selector: 'app', + providers: [DataListProvider], + template: ` + + `, +}) +class App { +} +// #enddocregion detach + +// #docregion reattach +class DataProvider { + data = 1; + constructor() { + setInterval(() => { this.data = 2; }, 500); + } +} + + +@Component({selector: 'live-data', inputs: ['live'], template: 'Data: {{dataProvider.data}}'}) +class LiveData { + constructor(private ref: ChangeDetectorRef, private dataProvider: DataProvider) {} + + set live(value: boolean) { + if (value) { + this.ref.reattach(); + } else { + this.ref.detach(); + } + } +} + +@Component({ + selector: 'app', + providers: [DataProvider], + template: ` + Live Update: + + `, +}) + +class App1 { + live = true; +} +// #enddocregion reattach