Skip to content
This repository was archived by the owner on Dec 4, 2017. It is now read-only.

Commit 4f87145

Browse files
kapunahelewongwardbell
authored andcommitted
docs(dyn-comp-loader): add explanations for methods, add doc structure, plunker (#3451)
1 parent cd0c363 commit 4f87145

File tree

3 files changed

+126
-59
lines changed

3 files changed

+126
-59
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"description": "Dynamic Component Loader",
3+
"basePath": "src/",
4+
"files":[
5+
"!**/*.d.ts",
6+
"!**/*.js"
7+
],
8+
"tags":["cookbook component"]
9+
}

public/docs/_examples/cb-dynamic-component-loader/ts/src/app/ad-banner.component.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ import { AdComponent } from './ad.component';
1111
template: `
1212
<div class="ad-banner">
1313
<h3>Advertisements</h3>
14-
<template ad-host></template>
14+
<ng-template ad-host></ng-template>
1515
</div>
1616
`
17-
// #enddocregion ad-host
17+
// #enddocregion ad-host
1818
})
19+
// #docregion class
1920
export class AdBannerComponent implements AfterViewInit, OnDestroy {
2021
@Input() ads: AdItem[];
2122
currentAddIndex: number = -1;
@@ -53,3 +54,4 @@ export class AdBannerComponent implements AfterViewInit, OnDestroy {
5354
}, 3000);
5455
}
5556
}
57+
// #enddocregion class

public/docs/ts/latest/cookbook/dynamic-component-loader.jade

Lines changed: 113 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,107 +3,158 @@ include ../_util-fns
33
:marked
44
Component templates are not always fixed. An application may need to load new components at runtime.
55

6-
In this cookbook we show how to use `ComponentFactoryResolver` to add components dynamically.
6+
This cookbook shows you how to use `ComponentFactoryResolver` to add components dynamically.
77

88
<a id="toc"></a>
99
:marked
10-
## Table of contents
10+
# Contents
1111

12-
[Dynamic Component Loading](#dynamic-loading)
12+
* [Dynamic component loading](#dynamic-loading)
13+
* [The directive](#directive)
14+
* [Loading components](#loading-components)
1315

14-
[Where to load the component](#where-to-load)
16+
* [Resolving Components](#resolving-components)
17+
* [Selector References](#selector-references)
1518

16-
[Loading components](#loading-components)
19+
* [A common _AdComponent_ interface](#common-interface)
20+
* [Final ad banner](#final-ad-banner)
21+
22+
:marked
23+
See the <live-example name="cb-dynamic-component-loader"></live-example>
24+
of the code in this cookbook.
1725

1826
.l-main-section
1927
<a id="dynamic-loading"></a>
2028
:marked
21-
## Dynamic Component Loading
29+
## Dynamic component loading
30+
31+
The following example shows how to build a dynamic ad banner.
2232

23-
The following example shows how to build a dynamic ad banner.
24-
25-
The hero agency is planning an ad campaign with several different ads cycling through the banner.
33+
The hero agency is planning an ad campaign with several different
34+
ads cycling through the banner. New ad components are added
35+
frequently by several different teams. This makes it impractical
36+
to use a template with a static component structure.
2637

27-
New ad components are added frequently by several different teams. This makes it impractical to use a template with a static component structure.
28-
29-
Instead we need a way to load a new component without a fixed reference to the component in the ad banner's template.
38+
Instead, you need a way to load a new component without a fixed
39+
reference to the component in the ad banner's template.
3040

31-
Angular comes with its own API for loading components dynamically. In the following sections you will learn how to use it.
41+
Angular comes with its own API for loading components dynamically.
3242

3343

3444
.l-main-section
35-
<a id="where-to-load"></a>
45+
<a id="directive"></a>
3646
:marked
37-
## Where to load the component
47+
## The directive
3848

39-
Before components can be added we have to define an anchor point to mark where components can be inserted dynamically.
49+
Before you can add components you have to define an anchor point
50+
to tell Angular where to insert components.
4051

41-
The ad banner uses a helper directive called `AdDirective` to mark valid insertion points in the template.
52+
The ad banner uses a helper directive called `AdDirective` to
53+
mark valid insertion points in the template.
4254

4355
+makeExample('cb-dynamic-component-loader/ts/src/app/ad.directive.ts',null,'src/app/ad.directive.ts')(format='.')
4456

4557
:marked
46-
`AdDirective` injects `ViewContainerRef` to gain access to the view container of the element that will become the host of the dynamically added component.
47-
58+
`AdDirective` injects `ViewContainerRef` to gain access to the view
59+
container of the element that will host the dynamically added component.
60+
61+
In the `@Directive` decorator, notice the selector name, `ad-host`;
62+
that's what you use to apply the directive to the element.
63+
The next section shows you how.
64+
4865
.l-main-section
4966
<a id="loading-components"></a>
5067
:marked
5168
## Loading components
5269

53-
The next step is to implement the ad banner. Most of the implementation is in `AdBannerComponent`.
70+
Most of the ad banner implementation is in `ad-banner.component.ts`.
71+
To keep things simple in this example, the HTML is in the `@Component`
72+
decorator's `template` property as a template string.
5473

55-
We start by adding a `template` element with the `AdDirective` directive applied.
74+
The `<ng-template>` element is where you apply the directive you just made.
75+
To apply the `AdDirective`, recall the selector from `ad.directive.ts`,
76+
`ad-host`. Apply that to `<ng-template>` without the square brackets. Now Angular knows
77+
where to dynamically load components.
5678

57-
+makeTabs(
58-
`cb-dynamic-component-loader/ts/src/app/ad-banner.component.ts,
59-
cb-dynamic-component-loader/ts/src/app/ad.service.ts,
60-
cb-dynamic-component-loader/ts/src/app/ad-item.ts,
61-
cb-dynamic-component-loader/ts/src/app/app.module.ts,
62-
cb-dynamic-component-loader/ts/src/app/app.component.ts`,
63-
null,
64-
`ad-banner.component.ts,
65-
ad.service.ts,
66-
ad-item.ts,
67-
app.module.ts,
68-
app.component`
69-
)
79+
+makeExample('cb-dynamic-component-loader/ts/src/app/ad-banner.component.ts', 'ad-host' ,'src/app/ad-banner.component.ts (template)')(format='.')
7080

7181
:marked
72-
The `template` element decorated with the `ad-host` directive marks where dynamically loaded components will be added.
73-
74-
Using a `template` element is recommended since it doesn't render any additional output.
82+
The `<ng-template>` element is a good choice for dynamic components
83+
because it doesn't render any additional output.
7584

76-
+makeExample('cb-dynamic-component-loader/ts/src/app/ad-banner.component.ts', 'ad-host' ,'src/app/ad-banner.component.ts (template)')(format='.')
85+
a#resolving-components
86+
:marked
87+
### Resolving components
88+
89+
Take a closer look at the methods in `ad-banner.component.ts`.
90+
91+
`AdBannerComponent` takes an array of `AdItem` objects as input,
92+
which ultimately comes from `AdService`. `AdItem` objects specify
93+
the type of component to load and any data to bind to the
94+
component.`AdService` returns the actual ads making up the ad campaign.
95+
96+
Passing an array of components to `AdBannerComponent` allows for a
97+
dynamic list of ads without static elements in the template.
98+
99+
With its `getAds()` method, `AdBannerComponent` cycles through the array of `AdItems`
100+
and loads a new component every 3 seconds by calling `loadComponent()`.
101+
102+
+makeExample('cb-dynamic-component-loader/ts/src/app/ad-banner.component.ts', 'class' ,'src/app/ad-banner.component.ts (excerpt)')(format='.')
103+
104+
:marked
105+
The `loadComponent()` method is doing a lot of the heavy lifting here.
106+
Take it step by step. First, it picks an ad.
107+
108+
.l-sub-section
109+
:marked
110+
**How _loadComponent()_ chooses an ad**
111+
112+
The `loadComponent()` method chooses an ad using some math.
113+
114+
First, it sets the `currentAddIndex` by taking whatever it
115+
currently is plus one, dividing that by the length of the `AdItem` array, and
116+
using the _remainder_ as the new `currentAddIndex` value. Then, it uses that
117+
value to select an `adItem` from the array.
77118

78119
:marked
79-
### Resolving Components
120+
After `loadComponent()` selects an ad, it uses `ComponentFactoryResolver`
121+
to resolve a `ComponentFactory` for each specific component.
122+
The `ComponentFactory` then creates an instance of each component.
123+
124+
Next, you're targeting the `viewContainerRef` that
125+
exists on this specific instance of the component. How do you know it's
126+
this specific instance? Because it's referring to `adHost` and `adHost` is the
127+
directive you set up earlier to tell Angular where to insert dynamic components.
80128

81-
`AdBanner` takes an array of `AdItem` objects as input. `AdItem` objects specify the type of component to load and any data to bind to the component.
129+
As you may recall, `AdDirective` injects `ViewContainerRef` into its constructor.
130+
This is how the directive accesses the element that you want to use to host the dynamic component.
82131

83-
The ad components making up the ad campaign are returned from `AdService`.
84-
85-
Passing an array of components to `AdBannerComponent` allows for a dynamic list of ads without static elements in the template.
132+
To add the component to the template, you call `createComponent()` on `ViewContainerRef`.
86133

87-
`AdBannerComponent` cycles through the array of `AdItems` and loads the corresponding components on an interval. Every 3 seconds a new component is loaded.
134+
The `createComponent()` method returns a reference to the loaded component.
135+
Use that reference to interact with the component by assigning to its properties or calling its methods.
88136

89-
`ComponentFactoryResolver` is used to resolve a `ComponentFactory` for each specific component. The component factory is need to create an instance of the component.
137+
a#selector-references
138+
:marked
139+
#### Selector references
90140

91-
`ComponentFactories` are generated by the Angular compiler.
92-
93-
Generally the compiler will generate a component factory for any component referenced in a template.
94-
95-
With dynamically loaded components there are no selector references in the templates since components are loaded at runtime. In order to ensure that the compiler will still generate a factory, dynamically loaded components have to be added to their `NgModule`'s `entryComponents` array.
141+
Generally, the Angular compiler generates a `ComponentFactory`
142+
for any component referenced in a template. However, there are
143+
no selector references in the templates for
144+
dynamically loaded components since they load at runtime.
96145

146+
To ensure that the compiler still generates a factory,
147+
add dynamically loaded components to the `NgModule`'s `entryComponents` array:
97148
+makeExample('cb-dynamic-component-loader/ts/src/app/app.module.ts', 'entry-components' ,'src/app/app.module.ts (entry components)')(format='.')
98149

150+
a#common-interface
99151
:marked
100-
Components are added to the template by calling `createComponent` on the `ViewContainerRef` reference.
101-
102-
`createComponent` returns a reference to the loaded component. The component reference can be used to pass input data or call methods to interact with the component.
152+
### A common _AdComponent_ interface
103153

104-
In the Ad banner, all components implement a common `AdComponent` interface to standardize the api for passing data to the components.
154+
In the ad banner, all components implement a common `AdComponent` interface to
155+
standardize the API for passing data to the components.
105156

106-
Two sample components and the `AdComponent` interface are shown below:
157+
Here are two sample components and the `AdComponent` interface for reference:
107158

108159
+makeTabs(
109160
`cb-dynamic-component-loader/ts/src/app/hero-job-ad.component.ts,
@@ -113,9 +164,14 @@ include ../_util-fns
113164
`hero-job-ad.component.ts,
114165
hero-profile.component.ts,
115166
ad.component.ts`
116-
)
167+
)
117168

169+
a#final-ad-baner
118170
:marked
171+
### Final ad banner
119172
The final ad banner looks like this:
120173
figure.image-display
121-
img(src="/resources/images/cookbooks/dynamic-component-loader/ads.gif" alt="Ads")
174+
img(src="/resources/images/cookbooks/dynamic-component-loader/ads.gif" alt="Ads")
175+
176+
:marked
177+
See the <live-example name="cb-dynamic-component-loader"></live-example>.

0 commit comments

Comments
 (0)