docs(lifecycle-hooks): copy edits and update TOC (#3380)
This commit is contained in:
parent
82b490f44e
commit
2d61df1c27
|
@ -7,7 +7,7 @@ figure
|
||||||
img(src="/resources/images/devguide/lifecycle-hooks/hooks-in-sequence.png" alt="Us" align="left" style="width:200px; margin-left:-40px;margin-right:30px")
|
img(src="/resources/images/devguide/lifecycle-hooks/hooks-in-sequence.png" alt="Us" align="left" style="width:200px; margin-left:-40px;margin-right:30px")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
A component has a lifecycle managed by Angular itself.
|
A component has a lifecycle managed by Angular.
|
||||||
|
|
||||||
Angular creates it, renders it, creates and renders its children,
|
Angular creates it, renders it, creates and renders its children,
|
||||||
checks it when its data-bound properties change, and destroys it before removing it from the DOM.
|
checks it when its data-bound properties change, and destroys it before removing it from the DOM.
|
||||||
|
@ -19,32 +19,39 @@ figure
|
||||||
<br class="l-clear-both">
|
<br class="l-clear-both">
|
||||||
+ifDocsFor('ts|js')
|
+ifDocsFor('ts|js')
|
||||||
:marked
|
:marked
|
||||||
## Table of Contents
|
## Contents
|
||||||
* [Overview](#hooks-overview)
|
* [Component lifecycle hooks overview](#hooks-overview)
|
||||||
* [Each hook's purpose and timing](#hooks-purpose-timing)
|
* [Lifecycle sequence](#hooks-purpose-timing)
|
||||||
* [Interfaces are optional (technically)](#interface-optional)
|
* [Interfaces are optional (technically)](#interface-optional)
|
||||||
* [Other Angular lifecycle hooks](#other-lifecycle-hooks)
|
* [Other Angular lifecycle hooks](#other-lifecycle-hooks)
|
||||||
* [The lifecycle sample](#the-sample)
|
* [Lifecycle examples](#the-sample)
|
||||||
* [All](#peek-a-boo)
|
* [Peek-a-boo: all hooks](#peek-a-boo)
|
||||||
* [Spying OnInit and OnDestroy](#spy)
|
* [Spying OnInit and OnDestroy](#spy)
|
||||||
|
* [OnInit](#oninit)
|
||||||
|
* [OnDestroy](#ondestroy)
|
||||||
* [OnChanges](#onchanges)
|
* [OnChanges](#onchanges)
|
||||||
* [DoCheck](#docheck)
|
* [DoCheck](#docheck)
|
||||||
* [AfterViewInit and AfterViewChecked](#afterview)
|
* [AfterView](#afterview)
|
||||||
* [AfterContentInit and AfterContentChecked](#aftercontent)
|
* [Abide by the unidirectional data flow rule](#wait-a-tick)
|
||||||
|
* [AfterContent](#aftercontent)
|
||||||
|
* [Content projection](#content-projection)
|
||||||
|
* [AfterContent hooks](#aftercontent-hooks)
|
||||||
|
* [No unidirectional flow worries with _AfterContent_](#no-unidirectional-flow-worries)
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Try the <live-example></live-example>.
|
Try the <live-example></live-example>.
|
||||||
|
|
||||||
a#hooks-overview
|
a#hooks-overview
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Component lifecycle hooks
|
## Component lifecycle hooks overview
|
||||||
Directive and component instances have a lifecycle
|
Directive and component instances have a lifecycle
|
||||||
as Angular creates, updates, and destroys them.
|
as Angular creates, updates, and destroys them.
|
||||||
Developers can tap into key moments in that lifecycle by implementing
|
Developers can tap into key moments in that lifecycle by implementing
|
||||||
one or more of the *Lifecycle Hook* interfaces in the Angular `core` library.
|
one or more of the *lifecycle hook* interfaces in the Angular `core` library.
|
||||||
|
|
||||||
Each interface has a single hook method whose name is the interface name prefixed with `ng`.
|
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`
|
For example, the `OnInit` interface has a hook method named `ngOnInit()`
|
||||||
that Angular calls shortly after creating the component:
|
that Angular calls shortly after creating the component:
|
||||||
+makeExample('lifecycle-hooks/ts/src/app/peek-a-boo.component.ts', 'ngOnInit', 'peek-a-boo.component.ts (excerpt)')(format='.')
|
+makeExample('lifecycle-hooks/ts/src/app/peek-a-boo.component.ts', 'ngOnInit', 'peek-a-boo.component.ts (excerpt)')(format='.')
|
||||||
:marked
|
:marked
|
||||||
|
@ -65,77 +72,77 @@ table(width="100%")
|
||||||
th Purpose and Timing
|
th Purpose and Timing
|
||||||
|
|
||||||
tr(style=top)
|
tr(style=top)
|
||||||
td ngOnChanges
|
td <code>ngOnChanges()</code>
|
||||||
td
|
td
|
||||||
:marked
|
:marked
|
||||||
Respond when Angular (re)sets data-bound input properties.
|
Respond when Angular (re)sets data-bound input properties.
|
||||||
The method receives a `SimpleChanges` object of current and previous property values.
|
The method receives a `SimpleChanges` object of current and previous property values.
|
||||||
|
|
||||||
Called before `ngOnInit` and whenever one or more data-bound input properties change.
|
Called before `ngOnInit()` and whenever one or more data-bound input properties change.
|
||||||
|
|
||||||
tr(style=top)
|
tr(style=top)
|
||||||
td ngOnInit
|
td <code>ngOnInit()</code>
|
||||||
td
|
td
|
||||||
:marked
|
:marked
|
||||||
Initialize the directive/component after Angular first displays the data-bound properties
|
Initialize the directive/component after Angular first displays the data-bound properties
|
||||||
and sets the directive/component's input properties.
|
and sets the directive/component's input properties.
|
||||||
|
|
||||||
Called _once_, after the _first_ `ngOnChanges`.
|
Called _once_, after the _first_ `ngOnChanges()`.
|
||||||
|
|
||||||
tr(style=top)
|
tr(style=top)
|
||||||
td ngDoCheck
|
td <code>ngDoCheck()</code>
|
||||||
td
|
td
|
||||||
:marked
|
:marked
|
||||||
Detect and act upon changes that Angular can't or won't detect on its own.
|
Detect and act upon changes that Angular can't or won't detect on its own.
|
||||||
|
|
||||||
Called during every change detection run, immediately after `ngOnChanges` and `ngOnInit`.
|
Called during every change detection run, immediately after `ngOnChanges()` and `ngOnInit()`.
|
||||||
|
|
||||||
tr(style=top)
|
tr(style=top)
|
||||||
td ngAfterContentInit
|
td <code>ngAfterContentInit()</code>
|
||||||
td
|
td
|
||||||
:marked
|
:marked
|
||||||
Respond after Angular projects external content into the component's view.
|
Respond after Angular projects external content into the component's view.
|
||||||
|
|
||||||
Called _once_ after the first `NgDoCheck`.
|
Called _once_ after the first `ngDoCheck()`.
|
||||||
|
|
||||||
_A component-only hook_.
|
_A component-only hook_.
|
||||||
|
|
||||||
tr(style=top)
|
tr(style=top)
|
||||||
td ngAfterContentChecked
|
td <code>ngAfterContentChecked()</code>
|
||||||
td
|
td
|
||||||
:marked
|
:marked
|
||||||
Respond after Angular checks the content projected into the component.
|
Respond after Angular checks the content projected into the component.
|
||||||
|
|
||||||
Called after the `ngAfterContentInit` and every subsequent `NgDoCheck`.
|
Called after the `ngAfterContentInit()` and every subsequent `ngDoCheck()`.
|
||||||
|
|
||||||
_A component-only hook_.
|
_A component-only hook_.
|
||||||
|
|
||||||
tr(style=top)
|
tr(style=top)
|
||||||
td ngAfterViewInit
|
td <code>ngAfterViewInit()</code>
|
||||||
td
|
td
|
||||||
:marked
|
:marked
|
||||||
Respond after Angular initializes the component's views and child views.
|
Respond after Angular initializes the component's views and child views.
|
||||||
|
|
||||||
Called _once_ after the first `ngAfterContentChecked`.
|
Called _once_ after the first `ngAfterContentChecked()`.
|
||||||
|
|
||||||
_A component-only hook_.
|
_A component-only hook_.
|
||||||
|
|
||||||
tr(style=top)
|
tr(style=top)
|
||||||
td ngAfterViewChecked
|
td <code>ngAfterViewChecked()</code>
|
||||||
td
|
td
|
||||||
:marked
|
:marked
|
||||||
Respond after Angular checks the component's views and child views.
|
Respond after Angular checks the component's views and child views.
|
||||||
|
|
||||||
Called after the `ngAfterViewInit` and every subsequent `ngAfterContentChecked`.
|
Called after the `ngAfterViewInit` and every subsequent `ngAfterContentChecked()`.
|
||||||
|
|
||||||
_A component-only hook_.
|
_A component-only hook_.
|
||||||
|
|
||||||
tr(style=top)
|
tr(style=top)
|
||||||
td ngOnDestroy
|
td <code>ngOnDestroy</code>
|
||||||
td
|
td
|
||||||
:marked
|
:marked
|
||||||
Cleanup just before Angular destroys the directive/component.
|
Cleanup just before Angular destroys the directive/component.
|
||||||
Unsubscribe observables and detach event handlers to avoid memory leaks.
|
Unsubscribe Observables and detach event handlers to avoid memory leaks.
|
||||||
|
|
||||||
Called _just before_ Angular destroys the directive/component.
|
Called _just before_ Angular destroys the directive/component.
|
||||||
|
|
||||||
|
@ -143,7 +150,7 @@ table(width="100%")
|
||||||
a#interface-optional
|
a#interface-optional
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Interface are optional (technically)
|
## Interfaces are optional (technically)
|
||||||
|
|
||||||
The interfaces are optional for JavaScript and Typescript developers from a purely technical perspective.
|
The interfaces are optional for JavaScript and Typescript developers from a purely technical perspective.
|
||||||
The JavaScript language doesn't have interfaces.
|
The JavaScript language doesn't have interfaces.
|
||||||
|
@ -161,7 +168,7 @@ table(width="100%")
|
||||||
a#other-lifecycle-hooks
|
a#other-lifecycle-hooks
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Other lifecycle hooks
|
## Other Angular lifecycle hooks
|
||||||
|
|
||||||
Other Angular sub-systems may have their own lifecycle hooks apart from these component hooks.
|
Other Angular sub-systems may have their own lifecycle hooks apart from these component hooks.
|
||||||
|
|
||||||
|
@ -174,7 +181,7 @@ block other-angular-subsystems
|
||||||
|
|
||||||
.l-main-section#the-sample
|
.l-main-section#the-sample
|
||||||
:marked
|
:marked
|
||||||
## Lifecycle exercises
|
## Lifecycle examples
|
||||||
|
|
||||||
The <live-example></live-example>
|
The <live-example></live-example>
|
||||||
demonstrates the lifecycle hooks in action through a series of exercises
|
demonstrates the lifecycle hooks in action through a series of exercises
|
||||||
|
@ -211,14 +218,14 @@ table(width="100%")
|
||||||
td <a href="#onchanges">OnChanges</a>
|
td <a href="#onchanges">OnChanges</a>
|
||||||
td
|
td
|
||||||
:marked
|
:marked
|
||||||
See how Angular calls the `ngOnChanges` hook with a `changes` object
|
See how Angular calls the `ngOnChanges()` hook with a `changes` object
|
||||||
every time one of the component input properties changes.
|
every time one of the component input properties changes.
|
||||||
Shows how to interpret the `changes` object.
|
Shows how to interpret the `changes` object.
|
||||||
tr(style=top)
|
tr(style=top)
|
||||||
td <a href="#docheck">DoCheck</a>
|
td <a href="#docheck">DoCheck</a>
|
||||||
td
|
td
|
||||||
:marked
|
:marked
|
||||||
Implements an `ngDoCheck` method with custom change detection.
|
Implements an `ngDoCheck()` method with custom change detection.
|
||||||
See how often Angular calls this hook and watch it post changes to a log.
|
See how often Angular calls this hook and watch it post changes to a log.
|
||||||
tr(style=top)
|
tr(style=top)
|
||||||
td <a href="#afterview">AfterView</a>
|
td <a href="#afterview">AfterView</a>
|
||||||
|
@ -246,7 +253,7 @@ table(width="100%")
|
||||||
to the `CounterComponent` log where it watches log entries being created and destroyed.
|
to the `CounterComponent` log where it watches log entries being created and destroyed.
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The remainder of this chapter discusses selected exercises in further detail.
|
The remainder of this page discusses selected exercises in further detail.
|
||||||
|
|
||||||
a#peek-a-boo
|
a#peek-a-boo
|
||||||
.l-main-section
|
.l-main-section
|
||||||
|
@ -272,7 +279,7 @@ figure.image-display
|
||||||
:marked
|
:marked
|
||||||
Had the user clicked the *Update Hero* button, the log would show another `OnChanges` and two more triplets of
|
Had the user clicked the *Update Hero* button, the log would show another `OnChanges` and two more triplets of
|
||||||
`DoCheck`, `AfterContentChecked` and `AfterViewChecked`.
|
`DoCheck`, `AfterContentChecked` and `AfterViewChecked`.
|
||||||
Clearly these three hooks fire a *often*. Keep the logic in these hooks as lean as possible!
|
Clearly these three hooks fire *often*. Keep the logic in these hooks as lean as possible!
|
||||||
|
|
||||||
The next examples focus on hook details.
|
The next examples focus on hook details.
|
||||||
|
|
||||||
|
@ -293,13 +300,13 @@ a#spy
|
||||||
1. Angular calls hook methods for *directives* as well as components.<br><br>
|
1. Angular calls hook methods for *directives* as well as components.<br><br>
|
||||||
|
|
||||||
2. A spy directive can provide insight into a DOM object that you cannot change directly.
|
2. A spy directive can provide insight into a DOM object that you cannot change directly.
|
||||||
Obviously you can't touch the implementation of a native `div`.
|
Obviously you can't touch the implementation of a native `<div>`.
|
||||||
You can't modify a third party component either.
|
You can't modify a third party component either.
|
||||||
But you can watch both with a directive.
|
But you can watch both with a directive.
|
||||||
|
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The sneaky spy directive is simple, consisting almost entirely of `ngOnInit` and `ngOnDestroy` hooks
|
The sneaky spy directive is simple, consisting almost entirely of `ngOnInit()` and `ngOnDestroy()` hooks
|
||||||
that log messages to the parent via an injected `LoggerService`.
|
that log messages to the parent via an injected `LoggerService`.
|
||||||
|
|
||||||
+makeExample('lifecycle-hooks/ts/src/app/spy.directive.ts', 'spy-directive')(format=".")
|
+makeExample('lifecycle-hooks/ts/src/app/spy.directive.ts', 'spy-directive')(format=".")
|
||||||
|
@ -307,7 +314,7 @@ a#spy
|
||||||
:marked
|
:marked
|
||||||
You can apply the spy to any native or component element and it'll be initialized and destroyed
|
You can apply the spy to any native or component element and it'll be initialized and destroyed
|
||||||
at the same time as that element.
|
at the same time as that element.
|
||||||
Here it is attached to the repeated hero `<div>`
|
Here it is attached to the repeated hero `<div>`:
|
||||||
+makeExample('lifecycle-hooks/ts/src/app/spy.component.html', 'template')(format=".")
|
+makeExample('lifecycle-hooks/ts/src/app/spy.component.html', 'template')(format=".")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
|
@ -318,19 +325,20 @@ figure.image-display
|
||||||
img(src='/resources/images/devguide/lifecycle-hooks/spy-directive.gif' alt="Spy Directive")
|
img(src='/resources/images/devguide/lifecycle-hooks/spy-directive.gif' alt="Spy Directive")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Adding a hero results in a new hero `<div>`. The spy's `ngOnInit` logs that event.
|
Adding a hero results in a new hero `<div>`. The spy's `ngOnInit()` logs that event.
|
||||||
|
|
||||||
The *Reset* button clears the `heroes` list.
|
The *Reset* button clears the `heroes` list.
|
||||||
Angular removes all hero `<div>` elements from the DOM and destroys their spy directives at the same time.
|
Angular removes all hero `<div>` elements from the DOM and destroys their spy directives at the same time.
|
||||||
The spy's `ngOnDestroy` method reports its last moments.
|
The spy's `ngOnDestroy()` method reports its last moments.
|
||||||
|
|
||||||
The `ngOnInit` and `ngOnDestroy` methods have more vital roles to play in real applications.
|
The `ngOnInit()` and `ngOnDestroy()` methods have more vital roles to play in real applications.
|
||||||
|
a#oninit
|
||||||
|
:marked
|
||||||
|
### _OnInit()_
|
||||||
|
|
||||||
### OnInit
|
Use `ngOnInit()` for two main reasons:
|
||||||
|
1. To perform complex initializations shortly after construction.
|
||||||
Use `ngOnInit` for two main reasons:
|
1. To set up the component after Angular sets the input properties.
|
||||||
1. to perform complex initializations shortly after construction
|
|
||||||
1. to set up the component after Angular sets the input properties
|
|
||||||
|
|
||||||
Experienced developers agree that components should be cheap and safe to construct.
|
Experienced developers agree that components should be cheap and safe to construct.
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
|
@ -345,43 +353,46 @@ figure.image-display
|
||||||
created under test or before you decide to display it.
|
created under test or before you decide to display it.
|
||||||
Constructors should do no more than set the initial local variables to simple values.
|
Constructors should do no more than set the initial local variables to simple values.
|
||||||
|
|
||||||
An `ngOnInit` is a good place for a component to fetch its initial data. The
|
An `ngOnInit()` is a good place for a component to fetch its initial data. The
|
||||||
[Tutorial](../tutorial/toh-pt4.html#oninit) and [HTTP](server-communication.html#oninit) chapter
|
[Tour of Heroes Tutorial](../tutorial/toh-pt4.html#oninit) and [HTTP Client](server-communication.html#oninit)
|
||||||
show how.
|
guides show how.
|
||||||
|
|
||||||
|
|
||||||
Remember also that a directive's data-bound input properties are not set until _after construction_.
|
Remember also that a directive's data-bound input properties are not set until _after construction_.
|
||||||
That's a problem if you need to initialize the directive based on those properties.
|
That's a problem if you need to initialize the directive based on those properties.
|
||||||
They'll have been set when `ngOninit` runs.
|
They'll have been set when `ngOnInit()` runs.
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
The `ngOnChanges` method is your first opportunity to access those properties.
|
The `ngOnChanges()` method is your first opportunity to access those properties.
|
||||||
Angular calls `ngOnChanges` before `ngOnInit` ... and many times after that.
|
Angular calls `ngOnChanges()` before `ngOnInit()` and many times after that.
|
||||||
It only calls `ngOnInit` once.
|
It only calls `ngOnInit()` once.
|
||||||
:marked
|
:marked
|
||||||
You can count on Angular to call the `ngOnInit` method _soon_ after creating the component.
|
You can count on Angular to call the `ngOnInit()` method _soon_ after creating the component.
|
||||||
That's where the heavy initialization logic belongs.
|
That's where the heavy initialization logic belongs.
|
||||||
|
|
||||||
### OnDestroy
|
a#ondestroy
|
||||||
|
:marked
|
||||||
|
### _OnDestroy()_
|
||||||
|
|
||||||
Put cleanup logic in `ngOnDestroy`, the logic that *must* run before Angular destroys the directive.
|
Put cleanup logic in `ngOnDestroy()`, the logic that *must* run before Angular destroys the directive.
|
||||||
|
|
||||||
This is the time to notify another part of the application that the component is going away.
|
This is the time to notify another part of the application that the component is going away.
|
||||||
|
|
||||||
This is the place to free resources that won't be garbage collected automatically.
|
This is the place to free resources that won't be garbage collected automatically.
|
||||||
Unsubscribe from observables and DOM events. Stop interval timers.
|
Unsubscribe from Observables and DOM events. Stop interval timers.
|
||||||
Unregister all callbacks that this directive registered with global or application services.
|
Unregister all callbacks that this directive registered with global or application services.
|
||||||
You risk memory leaks if you neglect to do so.
|
You risk memory leaks if you neglect to do so.
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
|
a#onchanges
|
||||||
:marked
|
:marked
|
||||||
## OnChanges
|
## _OnChanges()_
|
||||||
|
|
||||||
Angular calls its `ngOnChanges` method whenever it detects changes to ***input properties*** of the component (or directive).
|
Angular calls its `ngOnChanges()` method whenever it detects changes to ***input properties*** of the component (or directive).
|
||||||
This example monitors the `OnChanges` hook.
|
This example monitors the `OnChanges` hook.
|
||||||
+makeExample('lifecycle-hooks/ts/src/app/on-changes.component.ts', 'ng-on-changes', 'OnChangesComponent (ngOnChanges)')(format=".")
|
+makeExample('lifecycle-hooks/ts/src/app/on-changes.component.ts', 'ng-on-changes', 'on-changes.component.ts (excerpt)')(format=".")
|
||||||
:marked
|
:marked
|
||||||
The `ngOnChanges` method takes an object that maps each changed property name to a
|
The `ngOnChanges()` method takes an object that maps each changed property name to a
|
||||||
[SimpleChange](../api/core/index/SimpleChange-class.html) object holding the current and previous property values.
|
[SimpleChange](../api/core/index/SimpleChange-class.html) object holding the current and previous property values.
|
||||||
This hook iterates over the changed properties and logs them.
|
This hook iterates over the changed properties and logs them.
|
||||||
|
|
||||||
|
@ -408,58 +419,60 @@ figure.image-display
|
||||||
The hero object *reference* didn't change so, from Angular's perspective, there is no change to report!
|
The hero object *reference* didn't change so, from Angular's perspective, there is no change to report!
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
|
a#docheck
|
||||||
:marked
|
:marked
|
||||||
## DoCheck
|
## _DoCheck()_
|
||||||
Use the `DoCheck` hook to detect and act upon changes that Angular doesn't catch on its own.
|
Use the `DoCheck` hook to detect and act upon changes that Angular doesn't catch on its own.
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
Use this method to detect a change that Angular overlooked.
|
Use this method to detect a change that Angular overlooked.
|
||||||
:marked
|
:marked
|
||||||
The *DoCheck* sample extends the *OnChanges* sample with the following `ngDoCheck` hook:
|
The *DoCheck* sample extends the *OnChanges* sample with the following `ngDoCheck()` hook:
|
||||||
+makeExample('lifecycle-hooks/ts/src/app/do-check.component.ts', 'ng-do-check', 'DoCheckComponent (ngDoCheck)')(format=".")
|
+makeExample('lifecycle-hooks/ts/src/app/do-check.component.ts', 'ng-do-check', 'DoCheckComponent (ngDoCheck)')(format=".")
|
||||||
:marked
|
:marked
|
||||||
This code inspects certain _values-of-interest_, capturing and comparing their current state against previous values.
|
This code inspects certain _values of interest_, capturing and comparing their current state against previous values.
|
||||||
It writes a special message to the log when there are no substantive changes to the `hero` or the `power`
|
It writes a special message to the log when there are no substantive changes to the `hero` or the `power`
|
||||||
so you can see how often `DoCheck` is called. The results are illuminating:
|
so you can see how often `DoCheck` is called. The results are illuminating:
|
||||||
|
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src='/resources/images/devguide/lifecycle-hooks/do-check-anim.gif' alt="DoCheck")
|
img(src='/resources/images/devguide/lifecycle-hooks/do-check-anim.gif' alt="DoCheck")
|
||||||
:marked
|
:marked
|
||||||
While the `ngDoCheck` hook can detect when the hero's `name` has changed, it has a frightful cost.
|
While the `ngDoCheck()` hook can detect when the hero's `name` has changed, it has a frightful cost.
|
||||||
This hook is called with enormous frequency —
|
This hook is called with enormous frequency—after _every_
|
||||||
after _every_ change detection cycle no matter where the change occurred.
|
change detection cycle no matter where the change occurred.
|
||||||
It's called over twenty times in this example before the user can do anything.
|
It's called over twenty times in this example before the user can do anything.
|
||||||
|
|
||||||
Most of these initial checks are triggered by Angular's first rendering of *unrelated data elsewhere on the page*.
|
Most of these initial checks are triggered by Angular's first rendering of *unrelated data elsewhere on the page*.
|
||||||
Mere mousing into another input box triggers a call.
|
Mere mousing into another `<input>` triggers a call.
|
||||||
Relatively few calls reveal actual changes to pertinent data.
|
Relatively few calls reveal actual changes to pertinent data.
|
||||||
Clearly our implementation must be very lightweight or the user experience will suffer.
|
Clearly our implementation must be very lightweight or the user experience suffers.
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
|
a#afterview
|
||||||
:marked
|
:marked
|
||||||
## AfterView
|
## AfterView
|
||||||
The *AfterView* sample explores the `AfterViewInit` and `AfterViewChecked` hooks that Angular calls
|
The *AfterView* sample explores the `AfterViewInit()` and `AfterViewChecked()` hooks that Angular calls
|
||||||
*after* it creates a component's child views.
|
*after* it creates a component's child views.
|
||||||
|
|
||||||
Here's a child view that displays a hero's name in an input box:
|
Here's a child view that displays a hero's name in an `<input>`:
|
||||||
+makeExample('lifecycle-hooks/ts/src/app/after-view.component.ts', 'child-view', 'ChildComponent')(format=".")
|
+makeExample('lifecycle-hooks/ts/src/app/after-view.component.ts', 'child-view', 'ChildComponent')(format=".")
|
||||||
:marked
|
:marked
|
||||||
The `AfterViewComponent` displays this child view *within its template*:
|
The `AfterViewComponent` displays this child view *within its template*:
|
||||||
+makeExample('lifecycle-hooks/ts/src/app/after-view.component.ts', 'template', 'AfterViewComponent (template)')(format=".")
|
+makeExample('lifecycle-hooks/ts/src/app/after-view.component.ts', 'template', 'AfterViewComponent (template)')(format=".")
|
||||||
:marked
|
:marked
|
||||||
The following hooks take action based on changing values *within the child view*
|
The following hooks take action based on changing values *within the child view*,
|
||||||
which can only be reached by querying for the child view via the property decorated with
|
which can only be reached by querying for the child view via the property decorated with
|
||||||
[@ViewChild](../api/core/index/ViewChild-decorator.html).
|
[@ViewChild](../api/core/index/ViewChild-decorator.html).
|
||||||
|
|
||||||
+makeExample('lifecycle-hooks/ts/src/app/after-view.component.ts', 'hooks', 'AfterViewComponent (class excerpts)')(format=".")
|
+makeExample('lifecycle-hooks/ts/src/app/after-view.component.ts', 'hooks', 'AfterViewComponent (class excerpts)')(format=".")
|
||||||
#wait-a-tick
|
a#wait-a-tick
|
||||||
:marked
|
:marked
|
||||||
### Abide by the unidirectional data flow rule
|
### Abide by the unidirectional data flow rule
|
||||||
The `doSomething` method updates the screen when the hero name exceeds 10 characters.
|
The `doSomething()` method updates the screen when the hero name exceeds 10 characters.
|
||||||
|
|
||||||
+makeExample('lifecycle-hooks/ts/src/app/after-view.component.ts', 'do-something', 'AfterViewComponent (doSomething)')(format=".")
|
+makeExample('lifecycle-hooks/ts/src/app/after-view.component.ts', 'do-something', 'AfterViewComponent (doSomething)')(format=".")
|
||||||
:marked
|
:marked
|
||||||
Why does the `doSomething` method wait a tick before updating `comment`?
|
Why does the `doSomething()` method wait a tick before updating `comment`?
|
||||||
|
|
||||||
Angular's unidirectional data flow rule forbids updates to the view *after* it has been composed.
|
Angular's unidirectional data flow rule forbids updates to the view *after* it has been composed.
|
||||||
Both of these hooks fire _after_ the component's view has been composed.
|
Both of these hooks fire _after_ the component's view has been composed.
|
||||||
|
@ -468,22 +481,25 @@ figure.image-display
|
||||||
block tick-methods
|
block tick-methods
|
||||||
:marked
|
:marked
|
||||||
The `LoggerService.tick_then()` postpones the log update
|
The `LoggerService.tick_then()` postpones the log update
|
||||||
for one turn of the browser's JavaScript cycle ... and that's just long enough.
|
for one turn of the browser's JavaScript cycle and that's just long enough.
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Here's *AfterView* in action
|
Here's *AfterView* in action:
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src='/resources/images/devguide/lifecycle-hooks/after-view-anim.gif' alt="AfterView")
|
img(src='/resources/images/devguide/lifecycle-hooks/after-view-anim.gif' alt="AfterView")
|
||||||
:marked
|
:marked
|
||||||
Notice that Angular frequently calls `AfterViewChecked`, often when there are no changes of interest.
|
Notice that Angular frequently calls `AfterViewChecked()`, often when there are no changes of interest.
|
||||||
Write lean hook methods to avoid performance problems.
|
Write lean hook methods to avoid performance problems.
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
|
a#aftercontent
|
||||||
:marked
|
:marked
|
||||||
## AfterContent
|
## AfterContent
|
||||||
The *AfterContent* sample explores the `AfterContentInit` and `AfterContentChecked` hooks that Angular calls
|
The *AfterContent* sample explores the `AfterContentInit()` and `AfterContentChecked()` hooks that Angular calls
|
||||||
*after* Angular projects external content into the component.
|
*after* Angular projects external content into the component.
|
||||||
|
|
||||||
|
a#content-projection
|
||||||
|
:marked
|
||||||
### Content projection
|
### Content projection
|
||||||
*Content projection* is a way to import HTML content from outside the component and insert that content
|
*Content projection* is a way to import HTML content from outside the component and insert that content
|
||||||
into the component's template in a designated spot.
|
into the component's template in a designated spot.
|
||||||
|
@ -495,7 +511,7 @@ figure.image-display
|
||||||
:marked
|
:marked
|
||||||
Consider this variation on the [previous _AfterView_](#afterview) example.
|
Consider this variation on the [previous _AfterView_](#afterview) example.
|
||||||
This time, instead of including the child view within the template, it imports the content from
|
This time, instead of including the child view within the template, it imports the content from
|
||||||
the `AfterContentComponent`'s parent. Here's the parent's template.
|
the `AfterContentComponent`'s parent. Here's the parent's template:
|
||||||
+makeExample('lifecycle-hooks/ts/src/app/after-content.component.ts', 'parent-template', 'AfterContentParentComponent (template excerpt)')(format=".")
|
+makeExample('lifecycle-hooks/ts/src/app/after-content.component.ts', 'parent-template', 'AfterContentParentComponent (template excerpt)')(format=".")
|
||||||
:marked
|
:marked
|
||||||
Notice that the `<my-child>` tag is tucked between the `<after-content>` tags.
|
Notice that the `<my-child>` tag is tucked between the `<after-content>` tags.
|
||||||
|
@ -513,12 +529,14 @@ figure.image-display
|
||||||
:marked
|
:marked
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
The tell-tale signs of *content projection* are (a) HTML between component element tags
|
The telltale signs of *content projection* are twofold:
|
||||||
and (b) the presence of `<ng-content>` tags in the component's template.
|
- HTML between component element tags.
|
||||||
|
- The presence of `<ng-content>` tags in the component's template.
|
||||||
|
a#aftercontent-hooks
|
||||||
:marked
|
:marked
|
||||||
### AfterContent hooks
|
### AfterContent hooks
|
||||||
*AfterContent* hooks are similar to the *AfterView* hooks.
|
*AfterContent* hooks are similar to the *AfterView* hooks.
|
||||||
The key difference is in the child component
|
The key difference is in the child component.
|
||||||
|
|
||||||
* The *AfterView* hooks concern `ViewChildren`, the child components whose element tags
|
* The *AfterView* hooks concern `ViewChildren`, the child components whose element tags
|
||||||
appear *within* the component's template.
|
appear *within* the component's template.
|
||||||
|
@ -526,17 +544,17 @@ figure.image-display
|
||||||
* The *AfterContent* hooks concern `ContentChildren`, the child components that Angular
|
* The *AfterContent* hooks concern `ContentChildren`, the child components that Angular
|
||||||
projected into the component.
|
projected into the component.
|
||||||
|
|
||||||
The following *AfterContent* hooks take action based on changing values in a *content child*
|
The following *AfterContent* hooks take action based on changing values in a *content child*,
|
||||||
which can only be reached by querying for it via the property decorated with
|
which can only be reached by querying for them via the property decorated with
|
||||||
[@ContentChild](../api/core/index/ContentChild-decorator.html).
|
[@ContentChild](../api/core/index/ContentChild-decorator.html).
|
||||||
|
|
||||||
+makeExample('lifecycle-hooks/ts/src/app/after-content.component.ts', 'hooks', 'AfterContentComponent (class excerpts)')(format=".")
|
+makeExample('lifecycle-hooks/ts/src/app/after-content.component.ts', 'hooks', 'AfterContentComponent (class excerpts)')(format=".")
|
||||||
|
|
||||||
a#no-unidirectional-flow-worries
|
a#no-unidirectional-flow-worries
|
||||||
:marked
|
:marked
|
||||||
### No unidirectional flow worries with _AfterContent..._
|
### No unidirectional flow worries with _AfterContent_
|
||||||
|
|
||||||
This component's `doSomething` method update's the component's data-bound `comment` property immediately.
|
This component's `doSomething()` method update's the component's data-bound `comment` property immediately.
|
||||||
There's no [need to wait](#wait-a-tick).
|
There's no [need to wait](#wait-a-tick).
|
||||||
|
|
||||||
Recall that Angular calls both *AfterContent* hooks before calling either of the *AfterView* hooks.
|
Recall that Angular calls both *AfterContent* hooks before calling either of the *AfterView* hooks.
|
||||||
|
|
Loading…
Reference in New Issue