一尘不染

动态添加和删除角度组件

html

当前的官方文档仅显示如何动态 更改 标签 的组件<ng-template>

我想实现的是,让我们说我有3个部分组成:headersection,并footer具有以下选择:

<app-header>
<app-section>
<app-footer>

再有6个按钮,这将增加或删除每个组件:Add HeaderAdd Section,和Add Footer

当我单击时Add Header,该页面将添加<app-header>到呈现它的页面中,因此该页面将包含:

<app-header>

然后,如果我单击Add Section两次,该页面现在将包含:

<app-header>
<app-section>
<app-section>

如果单击Add Footer,该页面现在将包含所有这些组件:

<app-header>
<app-section>
<app-section>
<app-footer>

可以在Angular中实现吗?请注意,这ngFor不是我要寻找的解决方案,因为它仅允许向页面添加相同的组件,而不是不同的组件。

编辑:ngIfngFor是不是我要找的模板已经预定的解决方案。我所寻找的是类似的堆栈component秒或一arraycomponentS其中,我们可以添加,删除和更改的任何索引array容易。

编辑2:为了更清楚,让我们有一个为什么ngFor不起作用的另一个例子。假设我们具有以下组件:

<app-header>
<app-introduction>
<app-camera>
<app-editor>
<app-footer>

现在出现了一个新组件,<app-description>用户希望在和之间插入该组件<app-editor>ngFor仅当有一个我想一遍又一遍地循环的组件时,它才起作用。但是对于不同的组件,ngFor此处失败。


阅读 290

收藏
2020-05-10

共1个答案

一尘不染

您可以尝试实现以下目标:通过使用动态创建组件ComponentFactoryResolver,然后将其注入ViewContainerRef。动态执行此操作的一种方法是将组件的类作为将创建和注入组件的函数的参数传递。

请参见下面的示例:

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

// Example component (can be any component e.g. app-header app-section)
import { DraggableComponent } from './components/draggable/draggable.component';

@Component({
  selector: 'app-root',
  template: `
    <!-- Pass the component class as an argument to add and remove based on the component class -->
    <button (click)="addComponent(draggableComponentClass)">Add</button>
    <button (click)="removeComponent(draggableComponentClass)">Remove</button>

    <div>
      <!-- Use ng-template to ensure that the generated components end up in the right place -->
      <ng-template #container>

      </ng-template>
    </div>

  `
})
export class AppComponent {
  @ViewChild('container', {read: ViewContainerRef}) container: ViewContainerRef;

  // Keep track of list of generated components for removal purposes
  components = [];

  // Expose class so that it can be used in the template
  draggableComponentClass = DraggableComponent;

  constructor(private componentFactoryResolver: ComponentFactoryResolver) {
  }

  addComponent(componentClass: Type<any>) {
    // Create component dynamically inside the ng-template
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(componentClass);
    const component = this.container.createComponent(componentFactory);

    // Push the component so that we can keep track of which components are created
    this.components.push(component);
  }

  removeComponent(componentClass: Type<any>) {
    // Find the component
    const component = this.components.find((component) => component.instance instanceof componentClass);
    const componentIndex = this.components.indexOf(component);

    if (componentIndex !== -1) {
      // Remove component from both view and array
      this.container.remove(this.container.indexOf(component));
      this.components.splice(componentIndex, 1);
    }
  }
}

笔记:

  1. 如果您希望以后更轻松地删除这些组件,可以在局部变量中跟踪它们,请参见this.components。或者,您可以遍历内的所有元素ViewContainerRef

  2. 您必须将组件注册为输入组件。在模块定义中,将组件注册为entryComponent(entryComponents: [DraggableComponent])。

2020-05-10