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

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

问题描述

目前的官方文档仅展示了如何动态更改组件< ng-template> 标签。 https://angular.io/guide/dynamic-component-loader



我想说的是,我有3个组件: header section footer 与以下选择器:

 < ;应用程序报头> 
< app-section>
< app-footer>

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



,当我点击添加标题时,页面会将< app-header> 添加到这个页面将包含:

 < app-header> 

然后如果我点击添加部分两次,该页面现在将包含:

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

如果我点击添加页脚,则页面现在将包含所有这些组件:

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

在Angular中可以实现这个功能吗?请注意, ngFor 并不是我正在寻找的解决方案,因为它只允许添加相同的组件,而不是将不同的组件添加到页面。



编辑:ngIf和ngFor不是我正在寻找的解决方案,因为模板已经预先确定。我正在寻找的东西就像是一堆组件或一个组件数组,我们可以轻松地添加,移除和更改数组的任何索引。



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

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

现在出现一个新组件,< app-description> code>,用户希望在其中插入< app-editor> 。 ngFor仅适用于有一个相同的组件,我想一遍又一遍地循环。但对于不同的组件,ngFor在这里失败。

解决方案

你想要实现的功能可以通过使用 ComponentFactoryResolver ,然后将它们注入到 ViewContainerRef 中。一种动态实现这一点的方法是将组件的类作为将创建并注入组件的函数的参数。



请看下面的例子:

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

//示例组件(可以是任何组件,例如app-header app-section)
从'./components/draggable/draggable.component'中导入{DraggableComponent};

@Component({
selector:'app-root',
template:`
<! - 将组件类作为参数传递以添加和(click)=addComponent(draggableComponentClass)>添加< / button>
< button(click)=removeComponent(draggableComponentClass) >删除< / button>

< div>
<! - 使用ng-template确保生成的组件在正确的位置 - >
< ng-template#container>

< / ng-template>
< / div>

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

//跟踪生成的组件列表以便删除目的
components = [];

//公开类以便它可以在模板中使用
draggableComponentClass = DraggableComponent;

构造函数(private componentFactoryResolver:ComponentFactoryResolver){
}

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

//推送组件,以便我们可以跟踪哪些组件已创建
this.components.push(component);

$ b removeComponent(componentClass:Type< any>){
//查找组件
const component = this.components.find((component)=> ; component.instance instanceof componentClass);
const componentIndex = this.components.indexOf(component);

if(componentIndex!== -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天全站免登陆