angular-docs-cn/aio/content/cookbook/dynamic-component-loader.md

5.0 KiB

@title Dynamic Component Loader

@intro Load components dynamically

@description Component templates are not always fixed. An application may need to load new components at runtime.

In this cookbook we show how to use ComponentFactoryResolver to add components dynamically.

## Table of contents

Dynamic Component Loading

Where to load the component

Loading components

## Dynamic Component Loading

The following example shows how to build a dynamic ad banner.

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 we need a way to load a new component without a fixed reference to the component in the ad banner's template.

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

## Where to load the component

Before components can be added we have to define an anchor point to mark where components can be inserted dynamically.

The ad banner uses a helper directive called AdDirective to mark valid insertion points in the template.

{@example 'cb-dynamic-component-loader/ts/src/app/ad.directive.ts'}

AdDirective injects ViewContainerRef to gain access to the view container of the element that will become the host of the dynamically added component.

## Loading components

The next step is to implement the ad banner. Most of the implementation is in AdBannerComponent.

We start by adding a template element with the AdDirective directive applied.

{@example 'cb-dynamic-component-loader/ts/src/app/ad-banner.component.ts'} {@example 'cb-dynamic-component-loader/ts/src/app/ad.service.ts'} {@example 'cb-dynamic-component-loader/ts/src/app/ad-item.ts'} {@example 'cb-dynamic-component-loader/ts/src/app/app.module.ts'} {@example 'cb-dynamic-component-loader/ts/src/app/app.component.ts'}

The template element decorated with the ad-host directive marks where dynamically loaded components will be added.

Using a template element is recommended since it doesn't render any additional output.

{@example 'cb-dynamic-component-loader/ts/src/app/ad-banner.component.ts' region='ad-host'}

Resolving Components

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.

The ad components making up the ad campaign are returned from AdService.

Passing an array of components to AdBannerComponent allows for a dynamic list of ads without static elements in the template.

AdBannerComponent cycles through the array of AdItems and loads the corresponding components on an interval. Every 3 seconds a new component is loaded.

ComponentFactoryResolver is used to resolve a ComponentFactory for each specific component. The component factory is need to create an instance of the component.

ComponentFactories are generated by the Angular compiler.

Generally the compiler will generate a component factory for any component referenced in a template.

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.

{@example 'cb-dynamic-component-loader/ts/src/app/app.module.ts' region='entry-components'}

Components are added to the template by calling createComponent on the ViewContainerRef reference.

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.

In the Ad banner, all components implement a common AdComponent interface to standardize the api for passing data to the components.

Two sample components and the AdComponent interface are shown below:

{@example 'cb-dynamic-component-loader/ts/src/app/hero-job-ad.component.ts'} {@example 'cb-dynamic-component-loader/ts/src/app/hero-profile.component.ts'} {@example 'cb-dynamic-component-loader/ts/src/app/ad.component.ts'}

The final ad banner looks like this:

Ads