问题陈述:我正在开发一个有角度的应用程序。在这个应用程序中,我有4个组件,命名如下,
- 公共组件
- 框一组件
- 方框二组件
- 方框三组件
现在;公共部件";负责通过在其"中的数组上迭代来渲染其内部的其余组件;。ts">文件所以我们有下面的对象数组,它为我们提供了这3个组件的选择器名称
[
{'componentName': "Box One", 'selector': "app-box-one"},
{'componentName': "Box Two", 'selector': "app-box-two"},
{'componentName': "Box Three", 'selector': "app-box-three"}
]
现在,我使用ngFor对数组进行迭代,如下所示,
<div *ngFor="let com of components;">
<com.selector> </com.selector> // not giving selector name
</div>
现在的问题是,<com.selector> </com.selector>
语句无法从对象中获取选择器名称,这是显而易见的,因为在angular中,我们使用字符串插值作为{{com.selector}}
来提取数据。
但是,问题是,我们不能在HTML标记的天使括号中使用插值所以,如果我写类似<{{com.selector}}>
</{{com.selector}}>
的东西,那么我会在浏览器控制台窗口中得到错误。
那么,我们如何从迭代的每个对象中提取HTML标记天使括号中的选择器名称呢
for循环每次迭代后的预期输出:
<div>
<app-box-one> </app-box-one>
// <app-box-two> </app-box-two>
// <app-box-three> </app-box-three>
</div>
按您想要的方式是不可能的。我建议您将体系结构更改为只使用一个组件来表示所有框(通过使用@Input()
装饰器传递给组件的状态进行参数化)。查看文档。
但是,如果您仍然想保留这种体系结构,一种方法是将HTML元素从父组件的typescript直接添加到DOM中(在ngAfterViewInit生命周期挂钩内)。但我不建议这样做。通常,总是可以修改体系结构,使其只使用一个参数化组件。从typescript修改DOM的唯一情况是使用canvas。
UPDATE:经过一些研究,我认为在运行时将组件添加到DOM的最简单方法是使用Angular的ViewContainerRef。
将在运行时加载其他组件的组件的类型脚本如下所示:
import {Component, AfterViewInit, ViewContainerRef} from '@angular/core';
import {Child1Component} from './child1/child1.component';
import {Child2Component} from './child2/child2.component';
@Component({
selector: 'app-root',
templateUrl: 'app.component.html',
styleUrls: ['app.component.scss'],
})
export class AppComponent implements AfterViewInit {
components: any[] = [Child1Component, Child2Component];
constructor(public viewContainerRef: ViewContainerRef) {}
ngAfterViewInit() {
this.loadComponent();
}
loadComponent(){
this.viewContainerRef.clear();
for(const component of this.components){
this.viewContainerRef.createComponent<typeof component>(component);
}
}
}
导入要动态加载的组件,用它们创建一个数组,然后用ViewContainerRef
加载它们。
有关完整示例,请查看此处的解释。
You can execute for loop into one function and emit component name by using service subject variable, then subscribe it to all components, if the emitted component name will be matched that time render that component
component 1( where you want to render component one by one)
components = [
{ 'componentName': "box-one-component", 'selector': "app-box-one" },
{ 'componentName': "box-two-component", 'selector': "app-box-two" },
{ 'componentName': "box-three-component", 'selector': "app-box-three" }
]
ngOnInit(): void {
for (let comp of this.components) {
this.service.currentComponent.next(comp.selector)
}
}
in service
public currentComponent = new Subject();
in component app-box-one
public subscription: Subscription;
render: boolean = false // if render value is truthy that time you need to show html page
ngOnInit(): void {
this.subscription = this.service.currentComponent.subscribe(name => {
if (name == "app-box-one") {
this.render = true;
}
})
}
ngOnDestroy(): void {
if(this.subscription){
this.subscription.unsubscribe()
}
}
do the same thing into another two
经过思考和一些研究,我得出结论,我将使用ngIf指令来保持解决方案的简单性
我还检查了@John Doe
的解决方案,并认为如果以这种方式实现,也应该有效。但是,由于我们只有4个组件需要动态呈现,因此使用ViewContainerRef
方法会增加额外的代码和平性,从而不必要地使解决方案变得复杂对于使用ViewContainerRef
方法的现场示例,请访问https://angular.io/guide/dynamic-component-loader
以下使用ngIf指令的解决方案对我有效:
<div *ngFor="let com of components;">
<ng-container *ngIf="com.componentName === 'Box One'">
<app-box-one> </app-box-one>
</ng-container>
<ng-container *ngIf="com.componentName === 'Box Two'">
<app-box-two> </app-box-two>
</ng-container>
<ng-container *ngIf="com.componentName === 'Box Three'">
<app-box-three> </app-box-three>
</ng-container>
</div>