我想 dynamically 创建 template . 这应该用于在 Runtime 构建 ComponentType
并将其放置(甚至替换)它在托管组件内的某个位置 .
直到RC4我使用 ComponentResolver
,但是使用RC5我收到消息:
不建议使用ComponentResolver进行动态编译 . 请将ComponentFactoryResolver与@ NgModule / @ Component.entryComponents或ANALYZE_FOR_ENTRY_COMPONENTS提供程序一起使用 . 对于仅运行时编译,您还可以使用Compiler.compileComponentSync / Async .
我发现了这个(官方的angular2)文件
Angular 2同步动态组件创建
并了解我可以使用其中之一
-
种类
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
属性类型,跳过一些用户的某些属性......) . 即这是一个例子,真正的配置可以生成更多不同和复杂的模板 .
template is changing ,所以我不能使用 ComponentFactoryResolver
并传递现有的...我需要 Compiler
的解决方案
AOT和JitCompiler(以前的RuntimeCompiler)
您是否希望将此功能与AOT一起使用(提前编译)?你得到了:
错误:静态解析符号值时出错 . 不支持函数调用 . 考虑使用对导出函数的引用替换函数或lambda(原始.ts文件中的位置65:17),在... / node_modules/@angular/compiler/src/compiler.d.ts中解析符号COMPILER_PROVIDERS,
请留下您的评论,在这里投票:
11 回答
编辑 - 与2.3.0(2016-12-07)相关
类似的主题在这里讨论Equivalent of $compile in Angular 2 . 我们需要使用
JitCompiler
和NgModule
. 在Angular2中阅读有关NgModule
的更多信息:在果壳中
有 a working plunker/example (动态模板,动态组件类型,动态模块,
JitCompiler
,......正在运行)校长是:
1) 创建模板
2) 在缓存中找到
ComponentFactory
- 转到 7)3) - 创建
Component
4) - 创建
Module
5) - 编译
Module
6) - 返回(和缓存供以后使用)
ComponentFactory
7) 使用 Target 和
ComponentFactory
创建动态实例Component
这是一个代码片段(更多的是here) - 我们的自定义构建器返回刚构建/缓存
ComponentFactory
并且视图目标占位符消耗以创建 DynamicComponent 的实例这就是它 - 简而言之 . 要了解更多详情,请阅读以下内容
.
TL&DR
观察一个plunker并回来阅读详细信息,以防一些代码片段需要更多解释
.
详细说明 - Angular2 RC6和运行时组件
下面是this scenario的描述,我们会的
创建一个模块
PartsModule:NgModule
(小块的持有者)创建另一个模块
DynamicModule:NgModule
,它将包含我们的动态组件(并动态引用PartsModule
)创建动态模板(简单方法)
创建新的
Component
类型(仅当模板已更改时)创建新的
RuntimeModule:NgModule
. 该模块将包含先前创建的Component
类型致电
JitCompiler.compileModuleAndAllComponentsAsync(runtimeModule)
获取ComponentFactory
创建
DynamicComponent
的实例 - View Target占位符的作业和ComponentFactory
将
@Inputs
分配给 new instance (从INPUT
切换到TEXTAREA
编辑),消耗@Outputs
NgModule
我们需要一个
NgModule
.所有小部件都有 one 模块,例如:
string-editor
,text-editor
(date-editor
,number-editor
...)第二个是我们动态物料处理的模块 . 它将包含托管组件和一些提供商..这将是单身人士 . 因此我们将以标准方式发布它们 - 用
forRoot()
最后,我们需要一个特殊的运行时模块..但是稍后将作为
DynamicTypeBuilder
job的一部分创建 .第四个模块,应用程序模块,是保持声明编译器提供程序的人:
在那里阅读(阅读)关于NgModule的更多信息:
Angular 2 RC5 - NgModules, Lazy Loading and AoT compilation
Angular Modules documentation
模板构建器
在我们的示例中,我们将处理此类实体的详细信息
要创建一个
template
,在plunker中我们使用这个简单/天真的构建器 .这里的一个技巧是 - 它构建一个模板,该模板使用一些已知属性,例如 entity . 这样的属性(-ies)必须是动态组件的一部分,我们将在下面创建它 .
为了使它更容易一些,我们可以使用接口来定义属性,我们的模板构建器可以使用它 . 这将由我们的动态组件类型实现 .
ComponentFactory构建器
这里非常重要的是要记住:
因此,我们正在触及我们解决方案的核心 . 构建器,将1)创建
ComponentType
2)创建它NgModule
3)编译ComponentFactory
4) cache 它以供以后重用 .我们需要获得的依赖:
以下是如何获取
ComponentFactory
的片段:这里有两个方法,它们代表了如何在运行时创建装饰类/类型的非常酷的方法 . 不仅
@Component
而且@NgModule
重要:
主机组件使用的ComponentFactory
最终作品是一个组件,它承载我们的动态组件的目标,例如,
<div #dynamicContentPlaceHolder></div>
. 我们得到它的引用并使用ComponentFactory
来创建一个组件 . 简而言之,这里是该组件的所有部分(如果需要,打开plunker here)我们首先总结一下导入语句:
我们只接收模板和组件构建器 . 接下来是我们的示例所需的属性(更多注释)
在这个简单的场景中,我们的托管组件没有任何
@Input
. 所以它不必对变化做出反应 . 但尽管存在这一事实(并准备好即将发生的变化) - 如果组件已经(首先)已经启动,我们需要引入一些标志 . 只有这样我们才能开始魔术 .最后,我们将使用我们的组件构建器,它刚刚编译/缓存
ComponentFacotry
. 我们的目标占位符将被要求用该工厂实例化 the Component .小扩展
此外,我们需要保持对已编译模板的引用..以便能够正确 destroy() 它,每当我们将更改它 .
完成了
这就是它 . 不要忘记 Destroy 动态构建的任何内容(ngOnDestroy) . 另外,如果唯一的区别是他们的模板,请务必 cache dynamic
types
和modules
.检查一切here
EDIT (26/08/2017) :下面的解决方案适用于Angular2和4.我已将其更新为包含模板变量并单击处理程序并使用Angular 4.3进行测试 .
对于Angular4,Ophir's answer中描述的ngComponentOutlet是一个更好的解决方案 . 但是现在呢does not support inputs & outputs . 如果[此PR]([https://github.com/angular/angular/pull/15362]](https://github.com/angular/angular/pull/15362])被接受,则可以通过该组件create事件返回的实例 .
ng-dynamic-component可能是最好和最简单的解决方案,但我还没有测试过 .
@Long Field的答案就是现场!这是另一个(同步)示例:
住在http://plnkr.co/edit/fdP9Oc .
我一定是迟到了,这里没有一个解决方案似乎对我有帮助 - 太乱了,觉得太多了解决方法 .
我最终做的是使用
Angular 4.0.0-beta.6
的ngComponentOutlet .这给了我所有写在动态组件文件中的最简单,最简单的解决方案 .
Short explanation:
my-component
- 动态组件呈现的组件DynamicComponent
- 要动态构建的组件,它在my-component中呈现Don't forget to upgrade all the angular libraries to ^Angular 4.0.0
希望这有帮助,祝你好运!
UPDATE
也适用于角5 .
I decided to compact everything I learned into one file . 与RC5之前相比,这里有很多东西需要考虑 . 请注意,此源文件包含AppModule和AppComponent .
我有一个简单的例子来展示如何做角度2 rc6动态组件 .
比如说,你有一个动态的html模板= template1并想要动态加载,首先包装到组件中
这里template1为html,可能包含ng2组件
从rc6开始,必须有@NgModule包装这个组件 . @NgModule,就像anglarJS 1中的模块一样,它解耦了ng2应用程序的不同部分,因此:
(这里导入RouterModule,就像我的例子中一样,我的html中有一些路由组件,你可以在后面看到)
现在您可以将DynamicModule编译为:
this.compiler.compileModuleAndAllComponentsAsync(DynamicModule).then( factory => factory.componentFactories.find(x => x.componentType === DynamicComponent))
我们需要在app.moudule.ts上面加载它,请看我的app.moudle.ts . 有关更多详细信息,请查看:https://github.com/Longfld/DynamicalRouter/blob/master/app/MyRouterLink.ts和app.moudle.ts
并看到演示:http://plnkr.co/edit/1fdAYP5PAbiHdJfTKgWo?p=preview
我想在Radim的这篇非常优秀的帖子之上添加一些细节 .
我采用了这个解决方案,并对它进行了一些研究并迅速遇到了一些限制 . 我将概述那些,然后给出解决方案 .
首先,我无法在动态细节内部渲染动态细节(基本上是彼此嵌套的动态UI) .
下一个问题是我想在解决方案中提供的部分内部呈现动态细节 . 初始解决方案也是不可能的 .
最后,无法在字符串编辑器等动态部件上使用模板URL .
我根据这篇文章提出了另一个问题,关于如何实现这些限制,可以在这里找到:
recursive dynamic template compilation in angular2
如果您遇到与我相同的问题,我将概述这些限制的答案,因为这使得解决方案更加灵活 . 让初始的plunker更新也很棒 .
要在彼此内部嵌套动态详细信息,您需要在 type.builder.ts 的import语句中添加DynamicModule.forRoot()
除此之外,不可能在其中一个部分中使用
<dynamic-detail>
是字符串编辑器或文本编辑器 .要启用它,您需要更改
parts.module.ts
和dynamic.module.ts
里面
parts.module.ts
你需要在DYNAMIC_DIRECTIVES
中添加DynamicDetail
同样在
dynamic.module.ts
中你必须删除dynamicDetail,因为它们现在是部分的一部分可以在这里找到一个工作修改的plunker:http://plnkr.co/edit/UYnQHF?p=preview(我没有解决这个问题,我只是信使:-D)
最后,无法在动态组件上创建的部件中使用模板 . 解决方案(或解决方法 . 我不确定它是否是一个角度错误或框架的错误使用)是在构造函数中创建编译器而不是注入它 .
然后使用
_compiler
进行编译,然后启用templateUrls .希望这有助于其他人!
最好的问候莫滕
关注Radmin的优秀答案,对于使用angular-cli版本1.0.0-beta.22及更高版本的每个人都需要进行一些调整 .
COMPILER_PROVIDERS
can no longer be imported (有关详细信息,请参阅angular-cli GitHub) .所以解决方法是在
providers
部分根本不使用COMPILER_PROVIDERS
和JitCompiler
,但是在类型构建器类中使用JitCompilerFactory
来代替'@angular/compiler':如您所见,它不是可注射的,因此与DI无依赖关系 . 此解决方案也适用于不使用的项目角-CLI .
只需使用ng-dynamic中的dynamicComponent指令解决了Angular 2 Final版本中的问题 .
用法:
其中template是您的动态模板,上下文可以设置为您希望模板绑定到的任何动态数据模型 .
我自己试图看看如何将RC4更新为RC5,因此我偶然发现了这个条目,动态组件创建的新方法对我来说仍然有点神秘,所以我不会在组件工厂解析器上提出任何建议 .
但是,我可以建议在这种情况下更清晰地创建组件 - 只需在模板中使用switch,根据某些条件创建字符串编辑器或文本编辑器,如下所示:
顺便说一下,[prop]表达式中的“[”有意义,这表示单向数据绑定,因此如果您知道不需要将属性绑定到变量,则可以甚至省略它们 .
这是从服务器生成的动态表单控件的示例 .
https://stackblitz.com/edit/angular-t3mmg6
此示例是动态表单控件是添加组件(这是您可以从服务器获取Formcontrols的地方) . 如果您看到addcomponent方法,则可以看到Forms控件 . 在这个例子中,我没有使用角度材料,但它有效(我正在使用@work) . 这是目标角度6,但适用于所有以前的版本 .
需要为AngularVersion 5及更高版本添加JITComplierFactory .
谢谢
维杰
在Ophir Stern的答案之上,这是一个与Angular 4中的AoT一起使用的变体 . 我唯一的问题是我无法将任何服务注入DynamicComponent,但我可以忍受 .
注意:我没有使用Angular 5进行测试 .
希望这可以帮助 .
干杯!