如何通过打字稿代码动态注入Angular2子组件? [英] How do I dynamically inject an Angular2 sub component via typescript code?

查看:83
本文介绍了如何通过打字稿代码动态注入Angular2子组件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

上下文-我正在尝试创建一个自定义下拉列表,其中可以包含许多组件.我可以通过<ng-content>标记完成此操作,但是我的团队顽固地坚持认为他们不喜欢这样做.他们希望能够几乎完全通过打字稿代码实例化此下拉列表.

Context - I'm trying to create a custom dropdown that can contain a number of components. I could accomplish this via the <ng-content> tag, but my team is stubbornly insisting that they don't like that. They want to be able to instantiate this dropdown almost entirely through typescript code.

我认为我可以通过DynamicComponentLoader来完成此操作,但是不幸的是,我发现的所有好的教程都使用了loadIntoLocation()函数,该函数现已消失.因此,相反,我尝试使用loadAsRoot()函数,但无法正常工作.

I think I could accomplish this through the DynamicComponentLoader, but unfortunately, all the good tutorials I've found use the loadIntoLocation() function, which is now gone. So instead I've tried to use the loadAsRoot() function, but it's not working.

这就是我想要做的:

Main.ts:

import { Component } from '@angular/core';
import { MyDropdown } from './MyDropdown';

@Component({
    selector: 'my-app',
    template: `
        <my-dropdown [contentModels]="dropdownContentModels"></my-dropdown>
    `
})
export class Main {
    dropdownContentModels: any[];
    constructor() {
        var someComponentModel = {selector: 'some-component', text: 'some'};
        var otherComponentModel = {selector: 'other-component', text: 'other'};
        this.dropdownContentModels = [someComponentModel, otherComponentModel];
    }
}

MyDropdown.ts:

MyDropdown.ts:

import { Component } from '@angular/core';
import { InjectComponent } from './InjectComponent';

@Component({
    selector: 'my-dropdown',
    inputs: ['contentModels'],
    directives: [InjectComponent],
    template: `
        <div class="btn-group" dropdown>
            <button type="button" dropdownToggle>My Dropdown</button>
            <div class="dropdown-menu" role="menu">
                <inject-component *ngFor="let item of contentModels" [model]="item"></inject-component>
            </div>
        </div>
    `
})
export class MyDropdown {
    contentModels: any[];
}

InjectComponent.ts:

InjectComponent.ts:

import { Component, DynamicComponentLoader, Injector } from '@angular/core';

@Component({
    selector: 'inject-component',
    inputs: ['model'],
    template: `
        <div #toreplace></div>
    `,
    providers: [DynamicComponentLoader, Injector]
})
export class InjectComponent {
    model: any;
    constructor(private dcl: DynamicComponentLoader, private injector: Injector) {}
    ngOnInit() {
        this.dcl.loadAsRoot(this.createWrapper(), '#toreplace', this.injector);
    }
    createWrapper(): any {
        var model = this.model;
        @Component({
            selector: model.selector + '-wrapper',
            template: '<' + model.selector + ' [model]="model"></' + model.selector + '>'
        })
        class Wrapper {
            model: any = model;
        }

        return Wrapper;
    }
}

但是我遇到了运行时异常例外:错误:未被捕获(承诺):只能添加到TokenMap!令牌:注入器"

But I'm getting the runtime exception "EXCEPTION: Error: Uncaught (in promise): Can only add to a TokenMap! Token: Injector"

更新! (感谢echonax):

InjectComponent.ts:

InjectComponent.ts:

import { Component, ComponentResolver, ViewChild, ViewContainerRef, 
    ComponentFactory, ComponentRef } from '@angular/core';

@Component({
    selector: 'inject-component',
    inputs: ['model'],
    template: `
        <div #toreplace></div>
    `
})
export class InjectComponent {
    model: any;
    @ViewChild('toreplace', {read: ViewContainerRef}) toreplace;
    componentRef: ComponentRef<any>;

    constructor(private resolver: ComponentResolver) {}

    ngOnInit() {
        this.resolver.resolveComponent(this.createWrapper()).then((factory:ComponentFactory<any>) => {
            this.componentRef = this.toreplace.createComponent(factory);
        });
    }
    createWrapper(): any {
        var model = this.model;
        @Component({
            selector: model.selector + '-wrapper',
            directives: [ model.directives ],
            template: '<' + model.selector + ' [model]="model"></' + model.selector + '>'
        })
        class Wrapper {
            model: any = model;
        }

        return Wrapper;
    }
}

推荐答案

您可以使用新的.createComponent()函数.

import {ComponentRef, Injectable, Component, Injector, ViewContainerRef, ViewChild,ComponentResolver, DynamicComponentLoader} from '@angular/core';

export class InjectComponent {
    @ViewChild('toreplace', {read: ViewContainerRef}) toreplace;   


    constructor(private dcl: DynamicComponentLoader, injector: Injector,private resolver: ComponentResolver) {}

...

    this.resolver.resolveComponent((this.createWrapper()).then((factory:ComponentFactory<any>) => {
          this.cmpRef = this.theBody.createComponent(factory)
        });

并删除providers: [DynamicComponentLoader, Injector]

以下是使用DynamicComponentLoader(在app.component.ts中)的示例插件: https://plnkr.co/edit/azoGdAUvDvCwJ3RsPXD6?p=preview

Here's an example plunker that uses DynamicComponentLoader (in app.component.ts): https://plnkr.co/edit/azoGdAUvDvCwJ3RsPXD6?p=preview

这篇关于如何通过打字稿代码动态注入Angular2子组件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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