gpt4 book ai didi

Angular - 在另一个组件中动态注入(inject)一个组件

转载 作者:太空狗 更新时间:2023-10-29 18:29:00 25 4
gpt4 key购买 nike

我正在开发一个小的 UI 组件框架来满足我的个人需求和乐趣。我正在开发一个 Tab 组件,出于测试目的,我需要在另一个组件 (TabComponent) 中动态注入(inject)一个组件 (TabContainerComponent)。下面是我的两个组件的代码:

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 方法中将其注入(inject)我的其他组件 (TabContainer) 内的占位符中:

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 通过单击“添加选项卡”按钮触发:

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 消息,并且可以看到一个新的 标签(但没有任何属性,这很奇怪)在 标签内,但 Angular 不会更新 Tab 组件 View (没有创建

  • )。我还尝试通过在 TabComponent 类中实现 OnChanges 接口(interface)来检查更改,但没有成功。

    有没有人有办法解决我的问题?

    附注:我不想使用一组 TabContainer 组件来测试 createComponent 方法。

    更新:

    演示:

    https://stackblitz.com/edit/angular-imeh71?embed=1&file=src/app/app.component.ts

    最佳答案

    这是我可以让它工作的方式 -

    Tab.component.ts

    将“选项卡”从 TabContainerComponent 数组更改为 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 添加新的标签容器组件。

    我认为 TabComponent 中的“ContentChildren”查询应该由新添加的组件更新,但事实并非如此。我尝试订阅 TabCompoent 中查询列表的“更改”,但它没有被触发。

    但我观察到 AppComponent 中的“ViewChildren”查询在每次添加新组件时都会更新。因此,我已将更新的应用程序组件的 QueryList 分配给 TabComponent 的 QueryList。

    工作演示可用here

    关于Angular - 在另一个组件中动态注入(inject)一个组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51495787/

  • 25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com