我想动态创建一个模板。这应该用于在运行时构建ComponentType,并将其放置(甚至替换)到宿主组件内部的某个位置。
直到RC4我使用ComponentResolver,但与RC5我得到以下消息:
ComponentResolver is deprecated for dynamic compilation.
Use ComponentFactoryResolver together with @NgModule/@Component.entryComponents or ANALYZE_FOR_ENTRY_COMPONENTS provider instead.
For runtime compile only, you can also use Compiler.compileComponentSync/Async.
我找到了这个文档(Angular 2同步动态组件创建)
你要明白我可以用任何一种
一种带有ComponentFactoryResolver的动态ngIf。如果我在@Component({entryComponents: [comp1, comp2],…})内部传递已知的组件-我可以使用.resolveComponentFactory(componentToRender);
真正的运行时编译,使用编译器…
但问题是如何使用编译器?上面的说明说,我应该调用:Compiler.compileComponentSync/Async -那么如何?
为例。我想为一种设置创建(基于一些配置条件)这种模板
<form>
<string-editor
[propertyName]="'code'"
[entity]="entity"
></string-editor>
<string-editor
[propertyName]="'description'"
[entity]="entity"
></string-editor>
...
在另一种情况下,这个(字符串编辑器被文本编辑器取代)
<form>
<text-editor
[propertyName]="'code'"
[entity]="entity"
></text-editor>
...
等等(根据属性类型设置不同的数字/日期/引用编辑器,为某些用户跳过一些属性……)例如,这是一个例子,实际的配置可以生成更多不同和复杂的模板。
模板正在改变,所以我不能使用ComponentFactoryResolver和传递现有的…我需要一个解决方案与编译器。
我一定是迟到了,这里没有一个解决方案对我有帮助——太乱了,感觉像是一个太多的变通办法。
我最终使用了Angular 4.0.0-beta。6 ngComponentOutlet。
这给了我最短、最简单的解决方案,所有这些都写在动态组件的文件中。
下面是一个简单的例子,它只是接收文本并将其放在模板中,但显然你可以根据自己的需要进行更改:
import {
Component, OnInit, Input, NgModule, NgModuleFactory, Compiler
} from '@angular/core';
@Component({
selector: 'my-component',
template: `<ng-container *ngComponentOutlet="dynamicComponent;
ngModuleFactory: dynamicModule;"></ng-container>`,
styleUrls: ['my.component.css']
})
export class MyComponent implements OnInit {
dynamicComponent;
dynamicModule: NgModuleFactory<any>;
@Input()
text: string;
constructor(private compiler: Compiler) {
}
ngOnInit() {
this.dynamicComponent = this.createNewComponent(this.text);
this.dynamicModule = this.compiler.compileModuleSync(this.createComponentModule(this.dynamicComponent));
}
protected createComponentModule (componentType: any) {
@NgModule({
imports: [],
declarations: [
componentType
],
entryComponents: [componentType]
})
class RuntimeComponentModule
{
}
// a module for just this Type
return RuntimeComponentModule;
}
protected createNewComponent (text:string) {
let template = `dynamically created template with text: ${text}`;
@Component({
selector: 'dynamic-component',
template: template
})
class DynamicComponent implements OnInit{
text: any;
ngOnInit() {
this.text = text;
}
}
return DynamicComponent;
}
}
简短说明:
My-component—动态组件在其中呈现的组件
DynamicComponent -要动态构建的组件,它在my-component内部呈现
别忘了把所有的angular库升级到^ angular 4.0.0
希望这对你有所帮助,祝你好运!
更新
同样适用于angular 5。
我想在Radim的这篇非常出色的文章上添加一些细节。
我采用了这个解决方案并研究了一段时间,很快就遇到了一些限制。我只列出这些,然后给出答案。
首先,我无法渲染动态细节在一个
dynamic-detail(基本上是将动态ui嵌套在彼此内部)。
下一个问题是我想在里面渲染一个动态细节
解决方案中提供的部件之一。这是
初始解也是不可能的。
最后,它不可能在动态部分使用模板url,如字符串编辑器。
我在这篇文章的基础上提出了另一个问题,关于如何实现这些限制,可以在这里找到:
在angar2中递归动态模板编译
如果您遇到与我相同的问题,我将概述这些限制的答案,因为这使解决方案更加灵活。这将是了不起的有最初的活塞更新,以及。
为了在彼此内部嵌套dynamic-detail,你需要在type.builder.ts的import语句中添加DynamicModule.forRoot()
protected createComponentModule (componentType: any) {
@NgModule({
imports: [
PartsModule,
DynamicModule.forRoot() //this line here
],
declarations: [
componentType
],
})
class RuntimeComponentModule
{
}
// a module for just this Type
return RuntimeComponentModule;
}
除此之外,在字符串编辑器或文本编辑器的一个部分中使用<dynamic-detail>是不可能的。
要启用它,您需要更改parts.module.ts和dynamic.module.ts
你需要在DYNAMIC_DIRECTIVES中添加DynamicDetail
export const DYNAMIC_DIRECTIVES = [
forwardRef(() => StringEditor),
forwardRef(() => TextEditor),
DynamicDetail
];
同样在dynamic.module.ts中,你必须删除dynamicDetail,因为它们现在是部件的一部分
@NgModule({
imports: [ PartsModule ],
exports: [ PartsModule],
})
一个工作的修改活塞可以在这里找到:http://plnkr.co/edit/UYnQHF?p=preview(我没有解决这个问题,我只是信使:-D)
最后,不可能在动态组件上创建的部件中使用templateurls。解决方案(或变通方案)。我不确定这是一个angular错误还是框架的错误使用)是在构造函数中创建一个编译器,而不是注入它。
private _compiler;
constructor(protected compiler: RuntimeCompiler) {
const compilerFactory : CompilerFactory =
platformBrowserDynamic().injector.get(CompilerFactory);
this._compiler = compilerFactory.createCompiler([]);
}
然后使用_compiler进行编译,然后也启用templateUrls。
return new Promise((resolve) => {
this._compiler
.compileModuleAndAllComponentsAsync(module)
.then((moduleWithFactories) =>
{
let _ = window["_"];
factory = _.find(moduleWithFactories.componentFactories, { componentType: type });
this._cacheOfFactories[template] = factory;
resolve(factory);
});
});
希望这能帮助到其他人!
致以最亲切的问候
Morten
我有一个简单的例子来展示如何做angular 2 rc6动态组件。
比方说,你有一个动态html template = template1,想要动态加载,首先包装成组件
@Component({template: template1})
class DynamicComponent {}
这里template1作为html,可能包含ng2组件
在rc6中,必须使用@NgModule来包装这个组件。@NgModule,就像anglarJS 1中的module一样,它解耦了ng2应用程序的不同部分,因此:
@Component({
template: template1,
})
class DynamicComponent {
}
@NgModule({
imports: [BrowserModule,RouterModule],
declarations: [DynamicComponent]
})
class DynamicModule { }
(这里导入RouterModule,在我的例子中,有一些路由组件在我的html中,你可以在后面看到)
现在你可以这样编译DynamicModule:
this.compiler.compileModuleAndAllComponentsAsync (DynamicModule) (
factory => factory. componentfactories .find(x => x.p omenttype === DynamicComponent)
我们需要把上面的内容放到app. module .ts中来加载,请查看我的app.moudle.ts。
更多详细信息请查看:
https://github.com/Longfld/DynamicalRouter/blob/master/app/MyRouterLink.ts和app.moudle.ts
并查看演示:http://plnkr.co/edit/1fdAYP5PAbiHdJfTKgWo?p=preview