如何在 <ng-template> 的指定位置以编程方式注入组件?

How to inject component programatically at specified place of <ng-template>?

如何以编程方式实例化组件并将其插入到模板中的指定位置?

Stackblitz:https://stackblitz.com/edit/angular-do71xk

import {Component, ComponentFactoryResolver, TemplateRef, ViewChild, ViewContainerRef, Type} from "@angular/core";

export interface PaneOptions {
  component: Type<any>;
  params?: any;
}

@Component({
  selector: 'app-manager',
  template: `
    <ng-template #paneContainer></ng-template> <!-- probably redundant -->

    <!-- window template -->
    <ng-template #paneTemplate>
      <div style="background: red">
        <h3>Window header</h3>
        <ng-template #paneBody></ng-template> <!-- or another ng-template -->
      </div>
    </ng-template>
  `
})
export class ManagerComponent {
  @ViewChild('paneContainer', {read: ViewContainerRef}) paneContainer: ViewContainerRef;
  @ViewChild('paneTemplate', {read: ViewContainerRef}) paneTemplateRef: ViewContainerRef;
  @ViewChild('paneTemplate', {read: TemplateRef}) paneTemplate: TemplateRef<any>;

  constructor(private componentFactoryResolver: ComponentFactoryResolver) {}

  addPane(options: PaneOptions) {

    // create embedded view of pane template
    const embeddedView = this.paneContainer.createEmbeddedView(this.paneTemplate);

    // resolve component and insert it into pane container
    // instead, we need to clone #paneTemplate and insert component within <ng-content>
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(options.component);
    const component = this.paneTemplateRef.createComponent(componentFactory);

    Object.assign(component.instance, options.params);
  }
}

当我尝试在内部 ng-template 中实例化组件时,这是不同的方法。

import {Component, ComponentFactoryResolver, TemplateRef, ViewChild, ViewContainerRef, Type} from "@angular/core";

export interface PaneOptions {
  component: Type<any>;
  params?: any;
}

@Component({
  selector: 'app-manager',
  template: `
    <ng-template #paneContainer></ng-template>

    <!-- pane template -->
    <ng-template #paneTemplate>
      <div style="background: red">
        <h3>Below within red area should be the inner component</h3>
        <ng-template #inner></ng-template>
      </div>
    </ng-template>
  `
})
export class ManagerComponent {
  @ViewChild('paneContainer', {read: ViewContainerRef}) paneContainer: ViewContainerRef;
  @ViewChild('inner', {read: ViewContainerRef}) innerTemplateRef: ViewContainerRef;
  @ViewChild('paneTemplate', {read: TemplateRef}) paneTemplate: TemplateRef<any>;

  constructor(private componentFactoryResolver: ComponentFactoryResolver) {}

  addPane(options: PaneOptions) {

    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(options.component);
    const component = this.innerTemplateRef.createComponent(componentFactory);
    Object.assign(component.instance, options.params);

    // create embedded view of pane template
    const embeddedView = this.paneContainer.createEmbeddedView(this.paneTemplate);
  }
}

Stackblitz:https://stackblitz.com/edit/angular-dzx7vz

但是,我得到错误:

Error: Cannot read property 'createComponent' of undefined

我正在使用 Angular 编写 window 管理器。是否可以将组件注入 window 模板的指定位置,然后将 window 插入主容器?我想保留对每个 window 的引用,以便能够进一步删除它。

您必须为此进行三项主要更改。

  1. 需要编写一个主机指令来托管您的动态 此处解释的组件 - https://angular.io/guide/dynamic-component-loader

  2. 使用

    抓住你的主机指令

    @ViewChild(HostDirective, {static: false}) hostDirective;

  3. 将组件加载延迟到下一次更改检测 - 使用 setTimeout

你可以参考这个 stackBlitz https://stackblitz.com/edit/angular-kbjr75