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.
我们需要一种新的组件加载方式,它不需要在广告条组件的模板中引用固定的组件。
Instead, you need a way to load a new component without a fixed
reference to the component in the ad banner's template.
Angular 自带的API就能支持动态加载组件。
Angular comes with its own API for loading components dynamically.
指令
The directive
在添加组件之前,先要定义一个锚点来告诉Angular要把组件插入到什么地方。
Before you can add components you have to define an anchor point
to tell Angular where to insert components.
广告条使用一个名叫AdDirective的辅助指令来在模板中标记出有效的插入点。
The ad banner uses a helper directive called AdDirective to
mark valid insertion points in the template.
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.
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.
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.
AdBannerComponent takes an array of AdItem objects as input,
which ultimately comes from AdService. AdItem objects specify
the type of component to load and any data to bind to the
component.AdService returns the actual ads making up the ad campaign.
First, it sets the currentAddIndex by taking whatever it
currently is plus one, dividing that by the length of the AdItem array, and
using the remainder as the new currentAddIndex value. Then, it uses that
value to select an adItem from the array.
After loadComponent() selects an ad, it uses ComponentFactoryResolver
to resolve a ComponentFactory for each specific component.
The ComponentFactory then creates an instance of each component.
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
directive you set up earlier to tell Angular where to insert dynamic components.
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.
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.
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.