typescript 如何通过打字稿代码动态注入 Angular2 子组件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37618222/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I dynamically inject an Angular2 sub component via typescript code?
提问by SnoopDougg
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.
上下文 - 我正在尝试创建一个可以包含多个组件的自定义下拉列表。我可以通过<ng-content>
标签来实现这一点,但我的团队顽固地坚持认为他们不喜欢那样。他们希望能够几乎完全通过打字稿代码来实例化这个下拉菜单。
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.
我想我可以通过 DynamicComponentLoader 来实现这一点,但不幸的是,我发现的所有优秀教程都使用了 loadIntoLocation() 函数,该函数现已消失。因此,我尝试使用 loadAsRoot() 函数,但它不起作用。
Here's what I'm trying to do:
这是我想要做的:
Main.ts:
主要.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:
注入组件.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;
}
}
But I'm getting the runtime exception "EXCEPTION: Error: Uncaught (in promise): Can only add to a TokenMap! Token: Injector"
但我收到运行时异常“异常:错误:未捕获(承诺):只能添加到 TokenMap!令牌:注入器”
Update! (Thanks to echonax):
更新!(感谢 echonax):
InjectComponent.ts:
注入组件.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;
}
}
采纳答案by eko
You can use the new .createComponent()
function.
您可以使用新.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)
});
and remove providers: [DynamicComponentLoader, Injector]
并删除 providers: [DynamicComponentLoader, Injector]
Here's an example plunker that uses DynamicComponentLoader (in app.component.ts): https://plnkr.co/edit/azoGdAUvDvCwJ3RsPXD6?p=preview
这是一个使用 DynamicComponentLoader(在 app.component.ts 中)的示例 plunker:https://plnkr.co/edit/azoGdAUvDvCwJ3RsPXD6 ?p =preview