我想动态创建一个模板。这应该用于在运行时构建 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 Synchronous Dynamic Component Creation )
并了解我可以使用
- 一种动态的
ngIf
和ComponentFactoryResolver
。如果我通过@Component({entryComponents: [comp1, comp2], ...})
内部的已知组件 - 我可以使用.resolveComponentFactory(componentToRender);
- 真正的运行时编译,用
Compiler
…
但问题是如何使用 Compiler
?上面的注释说我应该打电话: Compiler.compileComponentSync/Async
- 那怎么办?
例如。我想为一种设置创建 (基于一些配置条件) 这种模板
<form>
<string-editor
[propertyName]="'code'"
[entity]="entity"
></string-editor>
<string-editor
[propertyName]="'description'"
[entity]="entity"
></string-editor>
...
在另一种情况下,这个 ( string-editor
被替换为 text-editor
)
<form>
<text-editor
[propertyName]="'code'"
[entity]="entity"
></text-editor>
...
依此类推 (不同的编号/日期/参考 editors
按属性类型,为某些用户跳过了一些属性…) 。即这是一个示例,实际配置可能会生成更多不同和复杂的模板。
模板正在更改,因此我无法使用 ComponentFactoryResolver
并传递现有模板…我需要 Compiler
的解决方案。
原文由 Radim Köhler 发布,翻译遵循 CC BY-SA 4.0 许可协议
编辑 - 与 2.3.0 相关(2016-12-07)
此处讨论了类似的主题 Angular 2 中的 $compile 等效项。我们需要使用
JitCompiler
和NgModule
。在 Angular2 中阅读更多关于NgModule
的信息:简而言之
有 一个有效的插件/示例 (动态模板,动态组件类型,动态模块,
JitCompiler
,……在行动)主要是:
1) 创建模板
2) 在缓存中找到
ComponentFactory
- 转到 7)Component
Module
Module
ComponentFactory
7) 使用 Target 和
ComponentFactory
创建一个动态实例Component
这是一个代码片段 ( 这里 有更多) - 我们的自定义生成器正在返回刚刚构建/缓存的
ComponentFactory
并且视图目标占位符消耗以创建DynamicComponent
的实例就是这样——简而言之。要获取更多详细信息..请阅读以下内容
.
TL&DR
观察一个 plunker 并回来阅读详细信息,以防某些片段需要更多解释
.
详解——Angular2 RC6++ & 运行时组件
下面描述 这个场景,我们将
PartsModule:NgModule
(小件支架)DynamicModule:NgModule
,它将包含我们的动态组件 (和引用PartsModule
动态)Component
类型 (仅当模板已更改时)RuntimeModule:NgModule
。该模块将包含先前创建的Component
类型JitCompiler.compileModuleAndAllComponentsAsync(runtimeModule)
得到ComponentFactory
DynamicComponent
的实例 - View Target 占位符的作业和ComponentFactory
@Inputs
分配给 新实例 (从INPUT
切换到TEXTAREA
编辑) ,使用@Outputs
模块
我们需要一个
NgModule
s。所有小组件都将有 一个 模块,例如
string-editor
,text-editor
(date-editor
,number-editor
) …第二个将是我们的动态东西处理模块。它将包含托管组件和一些提供程序..这将是单例。因此,我们将以标准方式发布它们 - 使用
forRoot()
最后,我们将需要一个临时的运行时模块.. 但这将在以后创建,作为
DynamicTypeBuilder
作业的一部分。第四个模块,应用程序模块,是保持声明编译器提供程序的模块:
阅读 (阅读) 更多关于 NgModule 的信息:
模板 生成器
在我们的示例中,我们将处理此类 实体 的详细信息
要创建一个
template
,在这个 plunker 中,我们使用这个简单/幼稚的构建器。这里的一个技巧是 - 它构建了一个使用一组已知属性的模板,例如
entity
。这样的属性(-ies)必须是我们接下来要创建的动态组件的一部分。为了使它更容易一点,我们可以使用一个接口来定义我们的模板构建器可以使用的属性。这将由我们的动态组件类型实现。
A
ComponentFactory
建造者这里非常重要的是要记住:
因此,我们正在触及解决方案的核心。生成器将 1) 创建
ComponentType
2) 创建其NgModule
3) 编译ComponentFactory
4) 将其 缓存 以供以后重用。我们需要接收的依赖项:
以下是如何获得
ComponentFactory
的片段:这里有两种方法,它们代表了如何在运行时创建 装饰 类/类型的非常酷的方法。不仅
@Component
而且@NgModule
重要的:
ComponentFactory
由托管组件使用最后一块是一个组件,它承载我们动态组件的目标,例如
<div #dynamicContentPlaceHolder></div>
。我们得到它的引用并使用ComponentFactory
创建一个组件。简而言之,这里是该组件的所有部分 (如果需要, 请在此处打开 plunker )我们先总结一下import语句:
我们只接收模板和组件构建器。接下来是我们的示例所需的属性 (更多在评论中)
在这个简单的场景中,我们的托管组件没有任何
@Input
。所以它不必对变化做出反应。但是尽管有这个事实 (并为即将发生的变化做好准备) - 如果组件已经 (首先) 启动,我们需要引入一些标志。只有这样我们才能开始魔术。最后,我们将使用我们的组件构建器,以及它 刚刚编译/缓存 的
ComponentFacotry
。我们的 Target 占位符 将被要求用该工厂实例化Component
。小扩展
此外,我们需要保留对已编译模板的引用.. 以便能够正确地
destroy()
它,无论何时我们将更改它。完毕
差不多就是这样。不要忘记 销毁 任何动态构建的东西 (ngOnDestroy) 。此外,如果唯一的区别是它们的模板,请务必 缓存 动态
types
和modules
。在 这里 检查一切