| 
									
										
										
										
											2019-12-02 12:47:19 -08:00
										 |  |  | # Dynamic component loader
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | Component templates are not always fixed. An application may need to load new components at runtime. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | This cookbook shows you how to use `ComponentFactoryResolver` to add components dynamically. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-21 17:21:45 -07:00
										 |  |  | See the <live-example name="dynamic-component-loader"></live-example> | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | of the code in this cookbook. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | {@a dynamic-loading} | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | ## Dynamic component loading
 | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | The following example shows how to build a dynamic ad banner. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | The hero agency is planning an ad campaign with several different | 
					
						
							|  |  |  | ads cycling through the banner. New ad components are added | 
					
						
							|  |  |  | frequently by several different teams. This makes it impractical | 
					
						
							|  |  |  | to use a template with a static component structure. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | Instead, you need a way to load a new component without a fixed | 
					
						
							|  |  |  | reference to the component in the ad banner's template. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | Angular comes with its own API for loading components dynamically. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | {@a directive} | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-08 20:47:34 -07:00
										 |  |  | ## The anchor directive
 | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | Before you can add components you have to define an anchor point | 
					
						
							|  |  |  | to tell Angular where to insert components. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | The ad banner uses a helper directive called `AdDirective` to | 
					
						
							|  |  |  | mark valid insertion points in the template. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-20 20:40:17 +03:00
										 |  |  | <code-example path="dynamic-component-loader/src/app/ad.directive.ts" header="src/app/ad.directive.ts"></code-example> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | `AdDirective` injects `ViewContainerRef` to gain access to the view | 
					
						
							|  |  |  | container of the element that will host the dynamically added component. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | In the `@Directive` decorator, notice the selector name, `ad-host`; | 
					
						
							|  |  |  | that's what you use to apply the directive to the element. | 
					
						
							|  |  |  | The next section shows you how. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | {@a loading-components} | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | ## Loading components
 | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | Most of the ad banner implementation is in `ad-banner.component.ts`. | 
					
						
							|  |  |  | To keep things simple in this example, the HTML is in the `@Component` | 
					
						
							|  |  |  | decorator's `template` property as a template string. | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | The `<ng-template>` element is where you apply the directive you just made. | 
					
						
							|  |  |  | To apply the `AdDirective`, recall the selector from `ad.directive.ts`, | 
					
						
							|  |  |  | `ad-host`. Apply that to `<ng-template>` without the square brackets. Now Angular knows | 
					
						
							|  |  |  | where to dynamically load components. | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-20 20:40:17 +03:00
										 |  |  | <code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="ad-host" header="src/app/ad-banner.component.ts (template)"></code-example> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | The `<ng-template>` element is a good choice for dynamic components | 
					
						
							|  |  |  | because it doesn't render any additional output. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | {@a resolving-components} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-08 20:47:34 -07:00
										 |  |  | ## Resolving components
 | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | Take a closer look at the methods in `ad-banner.component.ts`. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | `AdBannerComponent` takes an array of `AdItem` objects as input, | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | which ultimately comes from `AdService`.  `AdItem` objects specify | 
					
						
							|  |  |  | the type of component to load and any data to bind to the | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | component.`AdService` returns the actual ads making up the ad campaign. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | Passing an array of components to `AdBannerComponent` allows for a | 
					
						
							|  |  |  | dynamic list of ads without static elements in the template. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | With its `getAds()` method, `AdBannerComponent` cycles through the array of `AdItems` | 
					
						
							|  |  |  | and loads a new component every 3 seconds by calling `loadComponent()`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-20 20:40:17 +03:00
										 |  |  | <code-example path="dynamic-component-loader/src/app/ad-banner.component.ts" region="class" header="src/app/ad-banner.component.ts (excerpt)"></code-example> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | The `loadComponent()` method is doing a lot of the heavy lifting here. | 
					
						
							|  |  |  | Take it step by step. First, it picks an ad. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-19 15:00:08 -07:00
										 |  |  | <div class="alert is-helpful"> | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | **How _loadComponent()_ chooses an ad** | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | The `loadComponent()` method chooses an ad using some math. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-02-12 16:34:38 -05:00
										 |  |  | First, it sets the `currentAdIndex` by taking whatever it | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | currently is plus one, dividing that by the length of the `AdItem` array, and | 
					
						
							| 
									
										
										
										
											2018-02-12 16:34:38 -05:00
										 |  |  | using the _remainder_ as the new `currentAdIndex` value. Then, it uses that | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | value to select an `adItem` from the array. | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-10 16:51:13 +01:00
										 |  |  | </div> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | After `loadComponent()` selects an ad, it uses `ComponentFactoryResolver` | 
					
						
							|  |  |  | to resolve a `ComponentFactory` for each specific component. | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | The `ComponentFactory` then creates an instance of each component. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | Next, you're targeting the `viewContainerRef` that | 
					
						
							|  |  |  | exists on this specific instance of the component. How do you know it's | 
					
						
							|  |  |  | this specific instance? Because it's referring to `adHost` and `adHost` is the | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | directive you set up earlier to tell Angular where to insert dynamic components. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | As you may recall, `AdDirective` injects `ViewContainerRef` into its constructor. | 
					
						
							|  |  |  | This is how the directive accesses the element that you want to use to host the dynamic component. | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | To add the component to the template, you call `createComponent()` on `ViewContainerRef`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The `createComponent()` method returns a reference to the loaded component. | 
					
						
							|  |  |  | Use that reference to interact with the component by assigning to its properties or calling its methods. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | {@a selector-references} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### Selector references
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Generally, the Angular compiler generates a `ComponentFactory` | 
					
						
							|  |  |  | for any component referenced in a template. However, there are | 
					
						
							|  |  |  | no selector references in the templates for | 
					
						
							|  |  |  | dynamically loaded components since they load at runtime. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To ensure that the compiler still generates a factory, | 
					
						
							|  |  |  | add dynamically loaded components to the `NgModule`'s `entryComponents` array: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-20 20:40:17 +03:00
										 |  |  | <code-example path="dynamic-component-loader/src/app/app.module.ts" region="entry-components" header="src/app/app.module.ts (entry components)"></code-example> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | {@a common-interface} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-08 20:47:34 -07:00
										 |  |  | ## The _AdComponent_ interface
 | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | In the ad banner, all components implement a common `AdComponent` interface to | 
					
						
							|  |  |  | standardize the API for passing data to the components. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Here are two sample components and the `AdComponent` interface for reference: | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | <code-tabs> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 13:29:59 +02:00
										 |  |  |   <code-pane header="hero-job-ad.component.ts" path="dynamic-component-loader/src/app/hero-job-ad.component.ts"> | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   </code-pane> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 13:29:59 +02:00
										 |  |  |   <code-pane header="hero-profile.component.ts" path="dynamic-component-loader/src/app/hero-profile.component.ts"> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  |   </code-pane> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-11 13:29:59 +02:00
										 |  |  |   <code-pane header="ad.component.ts" path="dynamic-component-loader/src/app/ad.component.ts"> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  |   </code-pane> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-27 16:08:53 +01:00
										 |  |  | </code-tabs> | 
					
						
							| 
									
										
										
										
											2017-02-22 18:09:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | {@a final-ad-baner} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-08 20:47:34 -07:00
										 |  |  | ## Final ad banner
 | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  |  The final ad banner looks like this: | 
					
						
							| 
									
										
										
										
											2017-03-30 20:04:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-11 14:47:51 -08:00
										 |  |  | <div class="lightbox"> | 
					
						
							|  |  |  |   <img src="generated/images/guide/dynamic-component-loader/ads-example.gif" alt="Ads"> | 
					
						
							|  |  |  | </div> | 
					
						
							| 
									
										
										
										
											2017-04-01 01:57:13 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-26 15:11:02 +03:00
										 |  |  | See the <live-example name="dynamic-component-loader"></live-example>. |