在Angular中动态添加和删除组件 [英] Dynamically ADDING and REMOVING Components in 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>,用户希望在其中插入
。 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);
}
}
}
注意:
-
如果您想稍后更轻松地删除组件,您可以在本地变量中追踪它们,请参阅
this.components
。或者,您可以遍历ViewContainerRef
中的所有元素。 -
您必须将组件注册为一个入口组件。在你的模块定义中注册你的组件作为一个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:
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 theViewContainerRef
.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屋!