diff --git a/aio/content/guide/glossary.md b/aio/content/guide/glossary.md index 256f402d8e..2aeef39eab 100644 --- a/aio/content/guide/glossary.md +++ b/aio/content/guide/glossary.md @@ -214,6 +214,13 @@ Read more about component classes, templates, and views in [Introduction to Angu See [workspace configuration](#cli-config) +{@a content-projection} + +## content projection + +A way to insert DOM content from outside a component into the component's view in a designated spot. + +For more information, see [Responding to changes in content](guide/lifecycle-hooks#content-projection). {@a custom-element} @@ -946,6 +953,19 @@ Read more about TypeScript at [typescriptlang.org](http://www.typescriptlang.org {@a U} +{@a unidirectional-data-flow} + +## unidirectional data flow + +A data flow model where the component tree is always checked for changes in one direction (parent to child), which prevents cycles in the change detection graph. + +In practice, this means that data in Angular flows downward during change detection. +A parent component can easily change values in its child components because the parent is checked first. +A failure could occur, however, if a child component tries to change a value in its parent during change detection (inverting the expected data flow), because the parent component has already been rendered. +In development mode, Angular throws the `ExpressionChangedAfterItHasBeenCheckedError` error if your app attempts to do this, rather than silently failing to render the new value. + +To avoid this error, a [lifecycle hook](guide/lifecycle-hooks) method that seeks to make such a change should trigger a new change detection run. The new run follows the same direction as before, but succeeds in picking up the new value. + {@a universal} ## Universal @@ -968,7 +988,7 @@ Angular renders a view under the control of one or more [directives](#directive) A [component](#component) class and its associated [template](#template) define a view. A view is specifically represented by a `ViewRef` instance associated with a component. A view that belongs immediately to a component is called a *host view*. -Views are typically collected into [view hierarchies](#view-tree). +Views are typically collected into [view hierarchies](#view-tree). Properties of elements in a view can change dynamically, in response to user actions; the structure (number and order) of elements in a view can't. diff --git a/aio/content/guide/lifecycle-hooks.md b/aio/content/guide/lifecycle-hooks.md index 40eecdb9d9..a4243b2866 100644 --- a/aio/content/guide/lifecycle-hooks.md +++ b/aio/content/guide/lifecycle-hooks.md @@ -1,45 +1,49 @@ -# Lifecycle hooks +# Hooking into the component lifecycle -A component has a lifecycle managed by Angular. +A component instance has a lifecycle that starts when Angular instantiates the component class and renders the component view along with its child views. +The lifecycle continues with change detection, as Angular checks to see when data-bound properties change, and updates both the view and the component instance as needed. +The lifecycle ends when Angular destroys the component instance and removes its rendered template from the DOM. +Directives have a similar lifecycle, as Angular creates, updates, and destroys instances in the course of execution. -Angular creates and renders components along with their children, checks when their data-bound properties change, and destroys them before removing them from the DOM. +Your application can use [lifecycle hook methods](guide/glossary#lifecycle-hook "Definition of lifecycle hook") to tap into key events in the lifecycle of a component or directive in order to initialize new instances, initiate change detection when needed, respond to updates during change detection, and clean up before deletion of instances. -Angular offers **lifecycle hooks** -that provide visibility into these key life moments and the ability to act when they occur. +## Prerequisites -A directive has the same set of lifecycle hooks. +Before working with lifecycle hooks, you should have a basic understanding of the following: + +* [TypeScript programming](https://www.typescriptlang.org/). +* Angular app-design fundamentals, as described in [Angular Concepts](guide/architecture "Introduction to fundamental app-design concepts"). {@a hooks-overview} -## Component lifecycle hooks overview +## Responding to lifecycle events -Directive and component instances have a lifecycle -as Angular creates, updates, and destroys them. -Developers can tap into key moments in that lifecycle by implementing -one or more of the *lifecycle hook* interfaces in the Angular `core` library. +You can respond to events in the lifecycle of a component or directive by implementing one or more of the *lifecycle hook* interfaces in the Angular `core` library. +The hooks give you the opportunity to act on a component or directive instance at the appropriate moment, as Angular creates, updates, or destroys that instance. -Each interface has a single hook method whose name is the interface name prefixed with `ng`. -For example, the `OnInit` interface has a hook method named `ngOnInit()` -that Angular calls shortly after creating the component: +Each interface defines the prototype for a single hook method, whose name is the interface name prefixed with `ng`. +For example, the `OnInit` interface has a hook method named `ngOnInit()`. If you implement this method in your component or directive class, Angular calls it shortly after checking the input properties for that component or directive for the first time. -No directive or component will implement all of the lifecycle hooks. -Angular only calls a directive/component hook method *if it is defined*. +You don't have to implement all (or any) of the lifecycle hooks, just the ones you need. {@a hooks-purpose-timing} -## Lifecycle sequence +### Lifecycle event sequence -*After* creating a component/directive by calling its constructor, Angular -calls the lifecycle hook methods in the following sequence at specific moments: +After your application instantiates a component or directive by calling its constructor, Angular calls the hook methods you have implemented at the appropriate point in the lifecycle of that instance. + +Angular executes hook methods in the following sequence. You can use them to perform the following kinds of operations. - + + - - + + + + @@ -60,10 +70,14 @@ calls the lifecycle hook methods in the following sequence at specific moments: + @@ -74,8 +88,12 @@ calls the lifecycle hook methods in the following sequence at specific moments: + @@ -85,7 +103,13 @@ calls the lifecycle hook methods in the following sequence at specific moments: + + + @@ -109,10 +139,15 @@ calls the lifecycle hook methods in the following sequence at specific moments: + + @@ -121,7 +156,11 @@ calls the lifecycle hook methods in the following sequence at specific moments: + + + +
HookPurpose and TimingHook methodPurposeTiming
@@ -47,9 +51,15 @@ calls the lifecycle hook methods in the following sequence at specific moments: - Respond when Angular (re)sets data-bound input properties. + Respond when Angular sets or resets data-bound input properties. The method receives a `SimpleChanges` object of current and previous property values. + Note that this happens very frequently, so any operation you perform here impacts performance significantly. + See details in [Using change detection hooks](#onchanges) in this document. + + + Called before `ngOnInit()` and whenever one or more data-bound input properties change. - Initialize the directive/component after Angular first displays the data-bound properties - and sets the directive/component's input properties. + Initialize the directive or component after Angular first displays the data-bound properties + and sets the directive or component's input properties. + See details in [Initializing a component or directive](#oninit) in this document. - Called _once_, after the _first_ `ngOnChanges()`. + + + Called once, after the first `ngOnChanges()`.
Detect and act upon changes that Angular can't or won't detect on its own. + See details and example in [Defining custom change detection](#docheck) in this document. - Called during every change detection run, immediately after `ngOnChanges()` and `ngOnInit()`. + + + Called immediately after `ngOnChanges()` on every change detection run, and immediately after `ngOnInit()` on the first run.
- Respond after Angular projects external content into the component's view / the view that a directive is in. + Respond after Angular projects external content into the component's view, or into the view that a directive is in. + + See details and example in [Responding to changes in content](#aftercontent) in this document. + + + Called _once_ after the first `ngDoCheck()`. @@ -97,9 +121,15 @@ calls the lifecycle hook methods in the following sequence at specific moments: - Respond after Angular checks the content projected into the directive/component. + Respond after Angular checks the content projected into the directive or component. - Called after the `ngAfterContentInit()` and every subsequent `ngDoCheck()`. + See details and example in [Responding to projected content changes](#aftercontent) in this document. + + + + Called after `ngAfterContentInit()` and every subsequent `ngDoCheck()`.
- Respond after Angular initializes the component's views and child views / the view that a directive is in. + Respond after Angular initializes the component's views and child views, or the view that contains the directive. + + See details and example in [Responding to view changes](#afterview) in this document. + + Called _once_ after the first `ngAfterContentChecked()`. -
- Respond after Angular checks the component's views and child views / the view that a directive is in. + Respond after Angular checks the component's views and child views, or the view that contains the directive. + + Called after the `ngAfterViewInit()` and every subsequent `ngAfterContentChecked()`. @@ -133,53 +172,32 @@ calls the lifecycle hook methods in the following sequence at specific moments: - Cleanup just before Angular destroys the directive/component. + Cleanup just before Angular destroys the directive or component. Unsubscribe Observables and detach event handlers to avoid memory leaks. + See details in [Cleaning up on instance destruction](#ondestroy) in this document. - Called _just before_ Angular destroys the directive/component. + + + Called immediately before Angular destroys the directive or component.
-{@a interface-optional} - -## Interfaces are optional (technically) - -The interfaces are optional for JavaScript and Typescript developers from a purely technical perspective. -The JavaScript language doesn't have interfaces. -Angular can't see TypeScript interfaces at runtime because they disappear from the transpiled JavaScript. - -Fortunately, they aren't necessary. -You don't have to add the lifecycle hook interfaces to directives and components to benefit from the hooks themselves. - -Angular instead inspects directive and component classes and calls the hook methods *if they are defined*. -Angular finds and calls methods like `ngOnInit()`, with or without the interfaces. - -Nonetheless, it's good practice to add interfaces to TypeScript directive classes -in order to benefit from strong typing and editor tooling. - -{@a other-lifecycle-hooks} - -## Other Angular lifecycle hooks - -Other Angular sub-systems may have their own lifecycle hooks apart from these component hooks. - -3rd party libraries might implement their hooks as well in order to give developers more -control over how these libraries are used. - {@a the-sample} -## Lifecycle examples +### Lifecycle example set The -demonstrates the lifecycle hooks in action through a series of exercises +demonstrates the use of lifecycle hooks through a series of exercises presented as components under the control of the root `AppComponent`. - -They follow a common pattern: a *parent* component serves as a test rig for +In each case a *parent* component serves as a test rig for a *child* component that illustrates one or more of the lifecycle hook methods. -Here's a brief description of each exercise: +The following table lists the exercises with brief descriptions. +The sample code is also used to illustrate specific tasks in the following sections. @@ -205,12 +223,9 @@ Here's a brief description of each exercise: @@ -220,9 +235,9 @@ Here's a brief description of each exercise: @@ -232,8 +247,8 @@ Here's a brief description of each exercise: @@ -243,8 +258,8 @@ Here's a brief description of each exercise: @@ -256,40 +271,87 @@ Here's a brief description of each exercise: Shows how to project external content into a component and how to distinguish projected content from a component's view children. - Demonstrates the `ngAfterContentInit` and `ngAfterContentChecked` hooks. + Demonstrates the `ngAfterContentInit()` and `ngAfterContentChecked()` hooks.
- Directives have lifecycle hooks too. - A `SpyDirective` can log when the element it spies upon is - created or destroyed using the `ngOnInit` and `ngOnDestroy` hooks. - - This example applies the `SpyDirective` to a `
` in an `ngFor` *hero* repeater - managed by the parent `SpyComponent`. + Shows how you can use lifecycle hooks with a custom directive. + The `SpyDirective` implements the `ngOnInit()` and `ngOnDestroy()` hooks, + and uses them to watch and report when an element goes in or out of the current view.
- See how Angular calls the `ngOnChanges()` hook with a `changes` object - every time one of the component input properties changes. - Shows how to interpret the `changes` object. + Demonstrates how Angular calls the `ngOnChanges()` hook + every time one of the component input properties changes, + and shows how to interpret the `changes` object passed to the hook method.
- Implements an `ngDoCheck()` method with custom change detection. - See how often Angular calls this hook and watch it post changes to a log. + Implements the `ngDoCheck()` method with custom change detection. + Watch the hook post changes to a log to see how often Angular calls this hook.
- Shows what Angular means by a *view*. - Demonstrates the `ngAfterViewInit` and `ngAfterViewChecked` hooks. + Shows what Angular means by a [view](guide/glossary#view "Definition of view."). + Demonstrates the `ngAfterViewInit()` and `ngAfterViewChecked()` hooks.
- Counter + Counter - Demonstrates a combination of a component and a directive - each with its own hooks. - - In this example, a `CounterComponent` logs a change (via `ngOnChanges`) - every time the parent component increments its input counter property. - Meanwhile, the `SpyDirective` from the previous example is applied - to the `CounterComponent` log where it watches log entries being created and destroyed. + Demonstrates a combination of a component and a directive, each with its own hooks.
-The remainder of this page discusses selected exercises in further detail. + +{@a oninit} + +## Initializing a component or directive + +Use the `ngOnInit()` method to perform the following initialization tasks. + +* Perform complex initializations outside of the constructor. + Components should be cheap and safe to construct. + You should not, for example, fetch data in a component constructor. + You shouldn't worry that a new component will try to contact a remote server when + created under test or before you decide to display it. + + An `ngOnInit()` is a good place for a component to fetch its initial data. + For an example, see the [Tour of Heroes tutorial](tutorial/toh-pt4#oninit). + +
+ + In [Flaw: Constructor does Real Work](http://misko.hevery.com/code-reviewers-guide/flaw-constructor-does-real-work/), Misko Hevery, Angular team lead, explains why you should avoid complex constructor logic. + +
+ +* Set up the component after Angular sets the input properties. + Constructors should do no more than set the initial local variables to simple values. + + Keep in mind that a directive's data-bound input properties are not set until _after construction_. + If you need to initialize the directive based on those properties, set them when `ngOnInit()` runs. + +
+ + The `ngOnChanges()` method is your first opportunity to access those properties. + Angular calls `ngOnChanges()` before `ngOnInit()`, but also many times after that. + It only calls `ngOnInit()` once. + +
+ +{@a ondestroy} + +## Cleaning up on instance destruction + +Put cleanup logic in `ngOnDestroy()`, the logic that must run before Angular destroys the directive. + +This is the place to free resources that won't be garbage-collected automatically. +You risk memory leaks if you neglect to do so. + +* Unsubscribe from Observables and DOM events. +* Stop interval timers. +* Unregister all callbacks that the directive registered with global or application services. + +The `ngOnDestroy()` method is also the time to notify another part of the application that the component is going away. + + +## General examples + +The following examples demonstrate the call sequence and relative frequency of the various lifecycle events, and how the hooks can be used separately or together for components and directives. {@a peek-a-boo} -## Peek-a-boo: all hooks +### Sequence and frequency of all lifecycle events -The `PeekABooComponent` demonstrates all of the hooks in one component. +To show how Angular calls the hooks in the expected order, the `PeekABooComponent` demonstrates all of the hooks in one component. -You would rarely, if ever, implement all of the interfaces like this. -The peek-a-boo exists to show how Angular calls the hooks in the expected order. +In practice you would rarely, if ever, implement all of the interfaces the way this demo does. -This snapshot reflects the state of the log after the user clicked the *Create...* button and then the *Destroy...* button. +The following snapshot reflects the state of the log after the user clicked the *Create...* button and then the *Destroy...* button.