角度-在另一个组件中动态注入一个组件 [英] Angular - Dynamically inject a component in another component

查看:85
本文介绍了角度-在另一个组件中动态注入一个组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为自己的个人需求和娱乐目的开发一些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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆