在 Angular 中动态添加和移除组件 [英] Dynamically ADDING and REMOVING Components in Angular
问题描述
目前的官方文档只展示了如何在
标签中动态更改组件内.https://angular.io/guide/dynamic-component-loader
我想要实现的是,假设我有 3 个组件:header
、section
和 footer
,带有以下选择器:
<应用部分><应用页脚>
然后有 6 个按钮可以添加或删除每个组件:Add Header
、Add Section
和 Add Footer
当我点击Add Header
时,页面会将
添加到呈现它的页面,因此页面将包含:
然后如果我点击 Add Section
两次,页面现在将包含:
<应用部分><应用部分>
如果我点击Add Footer
,页面现在将包含所有这些组件:
<应用部分><应用部分><应用页脚>
是否可以在 Angular 中实现这一点?请注意,ngFor
不是我正在寻找的解决方案,因为它只允许向页面添加相同的组件,而不是不同的组件.
ngIf
和 ngFor
不是我正在寻找的解决方案,因为模板已经预先确定.我正在寻找的是类似于 component
的堆栈或 component
的 array
,我们可以在其中添加、删除和更改任何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);}}}
注意事项:
如果您希望以后更轻松地移除组件,您可以在局部变量中跟踪它们,请参阅
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 component
s or an array
of component
s 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屋!