Home >Web Front-end >JS Tutorial >Teach you step by step how to create dynamic content using Angular CDK Portal

Teach you step by step how to create dynamic content using Angular CDK Portal

青灯夜游
青灯夜游forward
2021-08-17 10:37:292756browse

Teach you step by step how to create dynamic content using Angular CDK Portal

I have introduced the dynamic view insertion of the native API before, and the function can already meet most usage scenarios. However, there are some shortcomings. It has not yet solved the need to insert content outside the Angular application, and the instructions cannot have input and output interactions with dynamically inserted components.

Fortunately, Angular officially provides a set of component development kits Component Dev Kit (CDK) as a basic tool for the development of various Angular components. Among them, "Portal" is provided to assist in the creation of dynamic views. .

This "dynamic view" can be a component, TemplateRef or DOM element, corresponding to three Portal types (ComponentPortal, TemplatePortal, DomPortal). The abstract generic base class of the three of them is Portal8742468051c85b06f0a0af9e3e506b5c, which has three methods: attach (mount to the container), detach (remove from the container), isAttached (determine whether the view is mounted) ).

The container is also defined by an abstract class BasePortalOutlet, which is similar to the view and includes attach (mount the view to the container), detach (remove the view from the container), and dispose (destroy the container) , isAttached (whether there is a mounted view). Its main implementation is the DomPortalOutlet class. Used to mount three types of dynamic views.

Creating dynamic content

Let’s first look at the creation of three dynamic views.

ComponentPortal

Compared with the native API, it is very simple to create a dynamic component. You only need to pass the component class into ComponentPortal Just use the constructor.

this.componentPortal = new ComponentPortal(ExampleComponent);

You can pass in any custom component class to create a ComponentPortal object and then dynamically insert it into the view.

✨Note: It is recommended to use the Ivy compiler for versions after Angular 9. If it is an old version of the compiler, the component class passed in needs to be declared in the entryComponents of the Module, and this Module No lazy loading.

TemplatePortal

Compared with components, the construction of TemplatePortal has one more parameter (ViewContainerRef). You should be very familiar with it after reading the previous article. You need to rely on it to call createEmbeddedView() to create an embedded view. Here, through constructor injection, the ViewContainerRef instance of the current component is directly used.

<ng-template #testTemplate>
  <p>一些需要动态插入的内容.</p>
</ng-template>
@ViewChild(&#39;testTemplate&#39;) templatePortalContent: TemplateRef<any>;

constructor(private _viewContainerRef: ViewContainerRef) { }

ngAfterViewInit() {
  this.templatePortal = new TemplatePortal(
    this.templatePortalContent,
    this._viewContainerRef
  );
}

In addition to the constructor, TemplatePortal also has a command (CdkPortal) that can be easily created.

<ng-template cdkPortal>
  <p>一些需要动态插入的内容.</p>
</ng-template>

<!-- 或写作 -->

<!-- 和上面写法是一致的效果 -->
<p *cdkPortal>
  一些需要动态插入的内容.
</p>

Then you can get the instance of TemplatePortal through @ViewChild.

DomPortal

Just like the above example, get the Template instance by @ViewChild to create it, you can also get it similarly ElementRef to create dynamic DOM.

<div #domPortalContent><span>原生DOM内容</span></div>
@ViewChild(&#39;domPortalContent&#39;) domPortalContent: ElementRef<HTMLElement>;
ngAfterViewInit() {
  this.domPortal = new DomPortal(this.domPortalContent);
}

This DOM can be dynamically transferred to any location. It should be noted that after the transfer, the original data binding or bound instructions may no longer be updated.

Insert container

The previous three types of Portal all said that they can be rendered to any position, so how to render them specifically?

CdkPortOutlet

The easiest way is to pass the CdkPortOutlet command:

<div>
  <ng-template [cdkPortalOutlet]="anyPortal"></ng-template>
</div>

Pass to anyPortal Any Portal instance among the above three values ​​will be dynamically rendered to the current position.

Different from the native API instructions, it can automatically determine what type of Portal it is. In addition, it has an additional event: attached. Through this event, you can get the mounted component instance or TemplateRef. This also makes interacting with mounted components very convenient.

Constructing a container instance

But since it is said that it can be rendered to any location, it naturally also includes outside the Angular application. To render to the application In addition, we need to create a container instance through the constructor.

This container class is DomPortalOutlet, which is the implementation subclass of PortalOutlet. Its construction parameters are mainly: Element (the DOM node of the mounted view), ComponentFactoryResolver (same as the previous article, used to dynamically build components), appRef (the overall instance of the current Angular application), Injector (injector, used to pass dependencies ).

constructor(
  private viewContainerRef: ViewContainerRef,
  @Inject(DOCUMENT) private document: any,
  private injector: Injector,
  private componentFactoryResolver: ComponentFactoryResolver
) {
  // 在<body>下创建外部宿主元素
  const container = this.document.createElement(&#39;div&#39;);
  container.classList.add(&#39;outside-portal-container&#39;);
  this.outsideContainer = this.document.body.appendChild(container);
  // 获取应用实例
  this.appRef = this.injector.get(ApplicationRef);
  // 创建外部容器
  this.outsideOutlet = new DomPortalOutlet(
    this.outsideContainer, 
    this.componentFactoryResolver, 
    this.appRef, 
    this.injector
  );
}

// 在应用外部插入动态组件。
openComponentPortalOutSideAngularContext(): void {
  const componentPortal = new ComponentPortal(AlertComponent);
  const componentRef = this.outsideOutlet.attach(componentPortal);
    componentRef.instance.closeAlert.subscribe(() => {
      this.outsideOutlet.detach();
    });
}

// 在应用外部插入动态模板。
openTemplatePortalInsideAngularContext(): void {
  const templatePortal = new TemplatePortal(this.templatePortalContent, this.viewContainerRef);
  this.outsideOutlet.attach(templatePortal);
}

In addition to mounting the view into a DOM element outside the application, you also need to be able to interact with the view. Components can inject dependencies, and templates can pass in context objects.

const injectionToken = new InjectionToken<any>(&#39;Sharing data with outside component portal&#39;);
const customInjector = Injector.create({ providers: [{ provide: CustomInjectionToken, useValue: &#39;test value&#39; }] });

Slightly modify the code to create outsideContainer and pass in the customInjector as a parameter (instead of using the injector of the current component)

// 重点是第四个参数
new DomPortalOutlet(this.outsideContainer, this.componentFactoryResolver, this.appRef, customInjector);

Correspondingly, this component only needs to be injected according to this injectionToken Just rely on it:

constructor(@Inject(injectionToken) public customData: any) {}

It is relatively simple to pass the context to the template. When creating the TemplatePortal object, just pass in the context object:

// 重点是第三个参数
new TemplatePortal(this.templatePortalContent, this.viewContainerRef, { customData:&#39;test values&#39; });

Summary

Compared with the native API, CDK portal mainly implements:

  • The ability to dynamically insert views outside the application;

  • The ability to interact with view data inserted into the outside;

  • More convenient and flexible instructions.

With it, it becomes easier to create dynamic component containers, pop-up windows, floating menus, or even build a low-code design platform.

Project source code: https://github.com/locotor/angular-dynamic-view-example

Online example: https://coding-pages-bucket-1575455- 8137703-14801-541995-1303365836.cos-website.ap-beijing.myqcloud.com/

For more programming-related knowledge, please visit: Introduction to Programming! !

The above is the detailed content of Teach you step by step how to create dynamic content using Angular CDK Portal. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:juejin.cn. If there is any infringement, please contact admin@php.cn delete