角度-在另一个组件中动态注入一个组件 [英] Angular - Dynamically inject a component in another component
问题描述
我正在为自己的个人需求和娱乐目的开发一些UI组件框架.我正在开发Tab组件,并且出于测试目的,我需要将一个组件(TabContainerComponent)动态注入到另一个组件(TabComponent)中.下面是我的两个组件的代码:
I'm developping a little UI components framework for my personal needs and for fun. I'm developping a Tab component and for testing purpose, I need to inject dynamically a component (TabContainerComponent) inside another component (TabComponent). Below, the code of my two components:
tab.component.ts:
import {Component, ContentChildren} from "@angular/core";
import {TabContainerComponent} from "./tabContainer.component";
@Component({
selector: 'tab',
templateUrl: 'tab.component.html'
})
export class TabComponent {
@ContentChildren(TabContainerComponent)
tabs: TabContainerComponent[];
}
tab.component.html:
<ul>
<li *ngFor="let tab of tabs">{{ tab.title }}</li>
</ul>
<div>
<div *ngFor="let tab of tabs">
<ng-container *ngTemplateOutlet="tab.template"></ng-container>
</div>
<ng-content></ng-content>
</div>
tabContainer.component.ts:
import {Component, Input} from "@angular/core";
@Component({
selector: 'tab-container',
template: '<ng-container></ng-container>'
})
export class TabContainerComponent {
@Input()
title: string;
@Input()
template;
}
我使用ComponentFactoryResolver和ComponentFactory动态创建我的新组件(TabContainerComponent),然后通过addTab方法将其注入到其他组件(TabContainer)中的占位符中:
I used a ComponentFactoryResolver and a ComponentFactory to create dynamically my new component (TabContainerComponent), and inject it in a placeholder inside my other component (TabContainer), in the addTab method:
app.component.ts :
import {
Component, ViewChild, ComponentFactoryResolver, ComponentFactory,
ComponentRef, TemplateRef, ViewContainerRef
} from '@angular/core';
import {TabContainerComponent} from "./tabContainer.component";
import {TabComponent} from "./tab.component";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app';
@ViewChild(TabComponent)
tab: TabComponent;
@ViewChild('tabsPlaceholder', {read: ViewContainerRef})
public tabsPlaceholder: ViewContainerRef;
@ViewChild('newTab')
newTab: TemplateRef<any>;
constructor(private resolver: ComponentFactoryResolver) {
}
addTab(): void {
let factory: ComponentFactory<TabContainerComponent> = this.resolver.resolveComponentFactory(TabContainerComponent);
let tab: ComponentRef<TabContainerComponent> = this.tabsPlaceholder.createComponent(factory);
tab.instance.title = "New tab";
tab.instance.template = this.newTab;
console.log('addTab() triggered');
}
}
通过单击添加选项卡"按钮来触发addMethod:
The addMethod is triggered by clicking on the "Add tab" button:
app.component.html:
<button (click)="addTab()">Add tab</button>
<tab>
<tab-container title="Tab 1" [template]="tab1"></tab-container>
<tab-container title="Tab 2" [template]="tab2"></tab-container>
<ng-container #tabsPlaceholder></ng-container>
</tab>
<ng-template #tab1>T1 template</ng-template>
<ng-template #tab2>T2 template</ng-template>
<ng-template #newTab>
This is a new tab
</ng-template>
app.module.ts :
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import {TabContainerComponent} from "./tabContainer.component";
import {TabComponent} from "./tab.component";
@NgModule({
declarations: [
AppComponent,
TabComponent,
TabContainerComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent],
entryComponents: [
TabContainerComponent
]
})
export class AppModule { }
当我单击添加选项卡"按钮时,我可以看到console.log消息,并且可以看到一个新的< tab-container> < tab>标签,但Angular不会更新Tab组件视图(没有创建< li>和< div>).我还尝试通过在TabComponent类中实现OnChanges接口来检查更改,但没有成功.
When I click on the "Add tab" button, I'm able to see the console.log message and I'm able to see a new <tab-container> tag (but without any attribute, which is strange) inside the <tab> tag but Angular doesn't update the Tab component view (there is no <li> and <div> created). I tried also to check changes by implementing OnChanges interface in TabComponent class but without success.
有人有解决我问题的想法吗?
Is anyone have an idea to solve my problem ?
P.S .:我不想使用TabContainer组件数组来测试createComponent方法.
P.S.: I don't want to use an array of TabContainer components in order to test the createComponent method.
更新:
演示:
https://stackblitz. com/edit/angular-imeh71?embed = 1& file = src/app/app.component.ts
推荐答案
这是我可以使其工作的方式-
Here is the way I could make it work -
Tab.component.ts
将标签"从TabContainerComponent数组更改为QueryList.
Changed "tabs" from TabContainerComponent array to QueryList.
import { Component, ContentChildren, QueryList } from '@angular/core';
import { TabContainerComponent } from '../tab-container/tab-container.component';
@Component({
selector: 'app-tab',
templateUrl: 'tab.component.html'
})
export class TabComponent {
@ContentChildren(TabContainerComponent)
tabs: QueryList<TabContainerComponent>;
constructor() {}
}
在 app.component.html
<ng-template #tabContainerTemplate>
<app-tab-container title="New Tab" [template]="newTab"></app-tab-container>
</ng-template>
app.component.ts
import {
Component,
ViewChild,
TemplateRef,
ViewContainerRef,
AfterViewInit,
ViewChildren,
QueryList,
ChangeDetectorRef
} from '@angular/core';
import { TabContainerComponent } from './tab-container/tab-container.component';
import { TabComponent } from './tab/tab.component';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements AfterViewInit {
title = 'app';
changeId: string;
@ViewChild(TabComponent) tab: TabComponent;
@ViewChild('tabsPlaceholder', { read: ViewContainerRef })
public tabsPlaceholder: ViewContainerRef;
@ViewChild('tabContainerTemplate', { read: TemplateRef })
tabContainerTemplate: TemplateRef<null>;
@ViewChildren(TabContainerComponent)
tabList: QueryList<TabContainerComponent>;
constructor(private changeDetector: ChangeDetectorRef) {}
ngAfterViewInit() {}
addTab(): void {
this.tabsPlaceholder.createEmbeddedView(this.tabContainerTemplate);
this.tab.tabs = this.tabList;
this.changeDetector.detectChanges();
console.log('addTab() triggered');
}
}
为TabContainerComponent添加了ViewChildren查询.在addTab()中,使用createEmbeddedView添加了新的标签容器组件.
Added a ViewChildren query for TabContainerComponent. In addTab() used createEmbeddedView to add new tab container component.
我认为TabComponent中的"ContentChildren"查询应该由新添加的组件来更新,但事实并非如此.我已尝试为TabCompoent中的查询列表订阅更改",但不会被触发.
I thought that "ContentChildren" query in TabComponent should be updated by the newly added component but it doesn't. I have tried to subscribe to "changes" for the query list in TabCompoent but it doesn't get triggered.
但是我发现,每次添加新组件时,AppComponent中的"ViewChildren"查询都会更新.因此,我已将应用程序组件的更新的QueryList分配给TabComponent的QueryList.
But I observed that "ViewChildren" query in AppComponent got updated every time a new component is added. So I have assigned updated QueryList of app component to the QueryList of TabComponent.
可以在此处
这篇关于角度-在另一个组件中动态注入一个组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!