5 lines
13 KiB
JSON
5 lines
13 KiB
JSON
{
|
|
"id": "guide/dynamic-component-loader",
|
|
"title": "Dynamic component loader",
|
|
"contents": "\n\n\n<div class=\"github-links\">\n <a href=\"https://github.com/angular/angular/edit/master/aio/content/guide/dynamic-component-loader.md?message=docs%3A%20describe%20your%20change...\" aria-label=\"Suggest Edits\" title=\"Suggest Edits\"><i class=\"material-icons\" aria-hidden=\"true\" role=\"img\">mode_edit</i></a>\n</div>\n\n\n<div class=\"content\">\n <h1 id=\"dynamic-component-loader\">Dynamic component loader<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dynamic-component-loader#dynamic-component-loader\"><i class=\"material-icons\">link</i></a></h1>\n<p>Component templates are not always fixed. An application may need to load new components at runtime.</p>\n<p>This cookbook shows you how to use <code><a href=\"api/core/ComponentFactoryResolver\" class=\"code-anchor\">ComponentFactoryResolver</a></code> to add components dynamically.</p>\n<p>See the <live-example name=\"dynamic-component-loader\"></live-example>\nof the code in this cookbook.</p>\n<a id=\"dynamic-loading\"></a>\n<h2 id=\"dynamic-component-loading\">Dynamic component loading<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dynamic-component-loader#dynamic-component-loading\"><i class=\"material-icons\">link</i></a></h2>\n<p>The following example shows how to build a dynamic ad banner.</p>\n<p>The hero agency is planning an ad campaign with several different\nads cycling through the banner. New ad components are added\nfrequently by several different teams. This makes it impractical\nto use a template with a static component structure.</p>\n<p>Instead, you need a way to load a new component without a fixed\nreference to the component in the ad banner's template.</p>\n<p>Angular comes with its own API for loading components dynamically.</p>\n<a id=\"directive\"></a>\n<h2 id=\"the-anchor-directive\">The anchor directive<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dynamic-component-loader#the-anchor-directive\"><i class=\"material-icons\">link</i></a></h2>\n<p>Before you can add components you have to define an anchor point\nto tell Angular where to insert components.</p>\n<p>The ad banner uses a helper directive called <code>AdDirective</code> to\nmark valid insertion points in the template.</p>\n<code-example path=\"dynamic-component-loader/src/app/ad.directive.ts\" header=\"src/app/ad.directive.ts\">\nimport { <a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>, <a href=\"api/core/ViewContainerRef\" class=\"code-anchor\">ViewContainerRef</a> } from '@angular/core';\n\n@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>({\n selector: '[adHost]',\n})\nexport class AdDirective {\n constructor(public viewContainerRef: <a href=\"api/core/ViewContainerRef\" class=\"code-anchor\">ViewContainerRef</a>) { }\n}\n\n\n\n</code-example>\n<p><code>AdDirective</code> injects <code><a href=\"api/core/ViewContainerRef\" class=\"code-anchor\">ViewContainerRef</a></code> to gain access to the view\ncontainer of the element that will host the dynamically added component.</p>\n<p>In the <code>@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a></code> decorator, notice the selector name, <code>adHost</code>;\nthat's what you use to apply the directive to the element.\nThe next section shows you how.</p>\n<a id=\"loading-components\"></a>\n<h2 id=\"loading-components\">Loading components<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dynamic-component-loader#loading-components\"><i class=\"material-icons\">link</i></a></h2>\n<p>Most of the ad banner implementation is in <code>ad-banner.component.ts</code>.\nTo keep things simple in this example, the HTML is in the <code>@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a></code>\ndecorator's <code>template</code> property as a template string.</p>\n<p>The <code><ng-template></code> element is where you apply the directive you just made.\nTo apply the <code>AdDirective</code>, recall the selector from <code>ad.directive.ts</code>,\n<code>[adHost]</code>. Apply that to <code><ng-template></code> without the square brackets. Now Angular knows\nwhere to dynamically load components.</p>\n<code-example path=\"dynamic-component-loader/src/app/ad-banner.component.ts\" region=\"ad-host\" header=\"src/app/ad-banner.component.ts (template)\">\ntemplate: `\n <div class=\"ad-banner-example\">\n <h3>Advertisements</h3>\n <ng-template adHost></ng-template>\n </div>\n `\n\n</code-example>\n<p>The <code><ng-template></code> element is a good choice for dynamic components\nbecause it doesn't render any additional output.</p>\n<a id=\"resolving-components\"></a>\n<h2 id=\"resolving-components\">Resolving components<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dynamic-component-loader#resolving-components\"><i class=\"material-icons\">link</i></a></h2>\n<p>Take a closer look at the methods in <code>ad-banner.component.ts</code>.</p>\n<p><code>AdBannerComponent</code> takes an array of <code>AdItem</code> objects as input,\nwhich ultimately comes from <code>AdService</code>. <code>AdItem</code> objects specify\nthe type of component to load and any data to bind to the\ncomponent.<code>AdService</code> returns the actual ads making up the ad campaign.</p>\n<p>Passing an array of components to <code>AdBannerComponent</code> allows for a\ndynamic list of ads without static elements in the template.</p>\n<p>With its <code>getAds()</code> method, <code>AdBannerComponent</code> cycles through the array of <code>AdItems</code>\nand loads a new component every 3 seconds by calling <code>loadComponent()</code>.</p>\n<code-example path=\"dynamic-component-loader/src/app/ad-banner.component.ts\" region=\"class\" header=\"src/app/ad-banner.component.ts (excerpt)\">\nexport class AdBannerComponent implements <a href=\"api/core/OnInit\" class=\"code-anchor\">OnInit</a>, <a href=\"api/core/OnDestroy\" class=\"code-anchor\">OnDestroy</a> {\n @<a href=\"api/core/Input\" class=\"code-anchor\">Input</a>() ads: AdItem[];\n currentAdIndex = -1;\n @<a href=\"api/core/ViewChild\" class=\"code-anchor\">ViewChild</a>(AdDirective, {<a href=\"api/upgrade/static\" class=\"code-anchor\">static</a>: true}) adHost: AdDirective;\n interval: any;\n\n constructor(private componentFactoryResolver: <a href=\"api/core/ComponentFactoryResolver\" class=\"code-anchor\">ComponentFactoryResolver</a>) { }\n\n ngOnInit() {\n this.loadComponent();\n this.getAds();\n }\n\n ngOnDestroy() {\n clearInterval(this.interval);\n }\n\n loadComponent() {\n this.currentAdIndex = (this.currentAdIndex + 1) % this.ads.length;\n const adItem = this.ads[this.currentAdIndex];\n\n const componentFactory = this.componentFactoryResolver.resolveComponentFactory(adItem.component);\n\n const viewContainerRef = this.adHost.viewContainerRef;\n viewContainerRef.clear();\n\n const componentRef = viewContainerRef.createComponent<AdComponent>(componentFactory);\n componentRef.instance.data = adItem.data;\n }\n\n getAds() {\n this.interval = setInterval(() => {\n this.loadComponent();\n }, 3000);\n }\n}\n\n</code-example>\n<p>The <code>loadComponent()</code> method is doing a lot of the heavy lifting here.\nTake it step by step. First, it picks an ad.</p>\n<div class=\"alert is-helpful\">\n<p><strong>How <em>loadComponent()</em> chooses an ad</strong></p>\n<p>The <code>loadComponent()</code> method chooses an ad using some math.</p>\n<p>First, it sets the <code>currentAdIndex</code> by taking whatever it\ncurrently is plus one, dividing that by the length of the <code>AdItem</code> array, and\nusing the <em>remainder</em> as the new <code>currentAdIndex</code> value. Then, it uses that\nvalue to select an <code>adItem</code> from the array.</p>\n</div>\n<p>After <code>loadComponent()</code> selects an ad, it uses <code><a href=\"api/core/ComponentFactoryResolver\" class=\"code-anchor\">ComponentFactoryResolver</a></code>\nto resolve a <code><a href=\"api/core/ComponentFactory\" class=\"code-anchor\">ComponentFactory</a></code> for each specific component.\nThe <code><a href=\"api/core/ComponentFactory\" class=\"code-anchor\">ComponentFactory</a></code> then creates an instance of each component.</p>\n<p>Next, you're targeting the <code>viewContainerRef</code> that\nexists on this specific instance of the component. How do you know it's\nthis specific instance? Because it's referring to <code>adHost</code> and <code>adHost</code> is the\ndirective you set up earlier to tell Angular where to insert dynamic components.</p>\n<p>As you may recall, <code>AdDirective</code> injects <code><a href=\"api/core/ViewContainerRef\" class=\"code-anchor\">ViewContainerRef</a></code> into its constructor.\nThis is how the directive accesses the element that you want to use to host the dynamic component.</p>\n<p>To add the component to the template, you call <code>createComponent()</code> on <code><a href=\"api/core/ViewContainerRef\" class=\"code-anchor\">ViewContainerRef</a></code>.</p>\n<p>The <code>createComponent()</code> method returns a reference to the loaded component.\nUse that reference to interact with the component by assigning to its properties or calling its methods.</p>\n<a id=\"common-interface\"></a>\n<h2 id=\"the-adcomponent-interface\">The <em>AdComponent</em> interface<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dynamic-component-loader#the-adcomponent-interface\"><i class=\"material-icons\">link</i></a></h2>\n<p>In the ad banner, all components implement a common <code>AdComponent</code> interface to\nstandardize the API for passing data to the components.</p>\n<p>Here are two sample components and the <code>AdComponent</code> interface for reference:</p>\n<code-tabs>\n\n <code-pane header=\"hero-job-ad.component.ts\" path=\"dynamic-component-loader/src/app/hero-job-ad.component.ts\">\nimport { <a href=\"api/core/Component\" class=\"code-anchor\">Component</a>, <a href=\"api/core/Input\" class=\"code-anchor\">Input</a> } from '@angular/core';\n\nimport { AdComponent } from './ad.component';\n\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n template: `\n <div class=\"job-ad\">\n <h4>{{data.headline}}</h4>\n\n {{data.body}}\n </div>\n `\n})\nexport class HeroJobAdComponent implements AdComponent {\n @<a href=\"api/core/Input\" class=\"code-anchor\">Input</a>() data: any;\n\n}\n\n\n\n</code-pane>\n\n <code-pane header=\"hero-profile.component.ts\" path=\"dynamic-component-loader/src/app/hero-profile.component.ts\">\nimport { <a href=\"api/core/Component\" class=\"code-anchor\">Component</a>, <a href=\"api/core/Input\" class=\"code-anchor\">Input</a> } from '@angular/core';\n\nimport { AdComponent } from './ad.component';\n\n@<a href=\"api/core/Component\" class=\"code-anchor\">Component</a>({\n template: `\n <div class=\"hero-profile\">\n <h3>Featured Hero Profile</h3>\n <h4>{{data.name}}</h4>\n\n <p>{{data.bio}}</p>\n\n <strong>Hire this hero today!</strong>\n </div>\n `\n})\nexport class HeroProfileComponent implements AdComponent {\n @<a href=\"api/core/Input\" class=\"code-anchor\">Input</a>() data: any;\n}\n\n\n\n\n</code-pane>\n\n <code-pane header=\"ad.component.ts\" path=\"dynamic-component-loader/src/app/ad.component.ts\">\nexport interface AdComponent {\n data: any;\n}\n\n\n</code-pane>\n\n</code-tabs>\n<a id=\"final-ad-baner\"></a>\n<h2 id=\"final-ad-banner\">Final ad banner<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/dynamic-component-loader#final-ad-banner\"><i class=\"material-icons\">link</i></a></h2>\n<p> The final ad banner looks like this:</p>\n<div class=\"lightbox\">\n <img src=\"generated/images/guide/dynamic-component-loader/ads-example.gif\" alt=\"Ads\" width=\"480\" height=\"222\">\n</div>\n<p>See the <live-example name=\"dynamic-component-loader\"></live-example>.</p>\n\n \n</div>\n\n<!-- links to this doc:\n - api/core/ComponentFactory\n - api/core/ComponentFactoryResolver\n - guide/elements\n - guide/example-apps-list\n-->\n<!-- links from this doc:\n - api/core/Component\n - api/core/ComponentFactory\n - api/core/ComponentFactoryResolver\n - api/core/Directive\n - api/core/Input\n - api/core/OnDestroy\n - api/core/OnInit\n - api/core/ViewChild\n - api/core/ViewContainerRef\n - api/upgrade/static\n - guide/dynamic-component-loader#dynamic-component-loader\n - guide/dynamic-component-loader#dynamic-component-loading\n - guide/dynamic-component-loader#final-ad-banner\n - guide/dynamic-component-loader#loading-components\n - guide/dynamic-component-loader#resolving-components\n - guide/dynamic-component-loader#the-adcomponent-interface\n - guide/dynamic-component-loader#the-anchor-directive\n - https://github.com/angular/angular/edit/master/aio/content/guide/dynamic-component-loader.md?message=docs%3A%20describe%20your%20change...\n-->"
|
|
} |