在 Angular 中动态添加和移除组件 [英] Dynamically ADDING and REMOVING Components in Angular

查看:25
本文介绍了在 Angular 中动态添加和移除组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前的官方文档只展示了如何在标签中动态更改组件.https://angular.io/guide/dynamic-component-loader

我想要实现的是,假设我有 3 个组件:headersectionfooter,带有以下选择器:

<应用部分><应用页脚>

然后有 6 个按钮可以添加或删除每个组件:Add HeaderAdd SectionAdd Footer

当我点击Add Header时,页面会将添加到呈现它的页面,因此页面将包含:

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

<应用部分><应用部分>

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

<应用部分><应用部分><应用页脚>

是否可以在 Angular 中实现这一点?请注意,ngFor 不是我正在寻找的解决方案,因为它只允许向页面添加相同的组件,而不是不同的组件.

ngIfngFor 不是我正在寻找的解决方案,因为模板已经预先确定.我正在寻找的是类似于 component 的堆栈或 componentarray,我们可以在其中添加、删除和更改任何array 的索引很容易.

EDIT 2:为了更清楚,让我们举另一个例子来说明为什么 ngFor 不起作用.假设我们有以下组件:

<app-介绍><app-相机><应用编辑器><应用页脚>

现在出现了一个新组件 ,用户希望将其插入到 之间.ngFor 仅当我想一遍又一遍地循环一个相同的组件时才起作用.但是对于不同的组件,ngFor 在这里失败了.

解决方案

您可以通过使用 ComponentFactoryResolver 动态创建组件,然后将它们注入到 中来实现查看容器引用.动态执行此操作的一种方法是将组件的类作为将创建和注入组件的函数的参数传递.

见下面的例子:

import {成分,ComponentFactoryResolver,类型,视图子,视图容器引用来自'@angular/core';//示例组件(可以是任何组件,例如 app-header app-section)import { DraggableComponent } from './components/draggable/draggable.component';@成分({选择器:'app-root',模板:`<!-- 将组件类作为参数传递以根据组件类进行添加和删除 --><button(点击)="addComponent(draggableComponentClass)">添加</button><button (click)="removeComponent(draggableComponentClass)">Remove</button><div><!-- 使用 ng-template 确保生成的组件最终出现在正确的位置--><ng-template #container></ng-模板>

`})导出类 AppComponent {@ViewChild('container', {read: ViewContainerRef}) 容器:ViewContainerRef;//跟踪生成的组件列表以进行删除组件 = [];//公开类以便它可以在模板中使用draggableComponentClass = DraggableComponent;构造函数(私有 componentFactoryResolver:ComponentFactoryResolver){}添加组件(组件类:类型<任何>){//在 ng-template 中动态创建组件const componentFactory = this.componentFactoryResolver.resolveComponentFactory(componentClass);const 组件 = this.container.createComponent(componentFactory);//推送组件,以便我们可以跟踪创建了哪些组件this.components.push(component);}移除组件(组件类:类型<任何>){//找到组件const component = this.components.find((component) => component.instance instanceof componentClass);const componentIndex = this.components.indexOf(component);如果(组件索引!== -1){//从视图和数组中删除组件this.container.remove(this.container.indexOf(component));this.components.splice(componentIndex, 1);}}}

注意事项:

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

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

运行示例:https://plnkr.co/edit/mrXtE1ICw5yeIUke7wl5

欲了解更多信息:https://angular.io/guide/dynamic-component-loader

The current official docs only shows how to dynamically change components within an <ng-template> tag. https://angular.io/guide/dynamic-component-loader

What I want to achieve is, let's say I have 3 components: header, section, and footer with the following selectors:

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

And then there are 6 buttons that will add or remove each component: Add Header, Add Section, and Add Footer

and when I click Add Header, the page will add <app-header> to the page that renders it, so the page will contain:

<app-header>

And then if I click Add Section twice, the page will now contain:

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

And if I click Add Footer, the page will now contain all these components:

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

Is it possible to achieve this in Angular? Note that ngFor is not the solution I'm looking for, as it only allows to add the same components, not different components to a page.

EDIT: ngIf and ngFor is not the solution I'm looking for as the templates are already predetermined. What I am looking for is something like a stack of components or an array of components where we can add, remove, and change any index of the array easily.

EDIT 2: To make it more clear, let's have another example of why ngFor does not work. Let's say we have the following components:

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

Now here comes a new component, <app-description>, which the user wants to insert in between and <app-editor>. ngFor works only if there is one same component that I want to loop over and over. But for different components, ngFor fails here.

解决方案

What you're trying to achieve can be done by creating components dynamically using the ComponentFactoryResolver and then injecting them into a ViewContainerRef. One way to do this dynamically is by passing the class of the component as an argument of your function that will create and inject the component.

See example below:

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);
    }
  }
}

Notes:

  1. If you want to make it easier to remove the components later on, you can keep track of them in a local variable, see this.components. Alternatively you can loop over all the elements inside the ViewContainerRef.

  2. You have to register your component as an entry component. In your module definition register your component as an entryComponent (entryComponents: [DraggableComponent]).

Running example: https://plnkr.co/edit/mrXtE1ICw5yeIUke7wl5

For more information: https://angular.io/guide/dynamic-component-loader

这篇关于在 Angular 中动态添加和移除组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆