首先说明主旨意思,动态 template 模板
,表示 @Component(template:动态改变这里的内容
)。假设一个场景,如我未来计划开发的一个前端页面生成工具,通过json schema
或者drag and drop
方式动态来生成form
,并且支持代码下载和复制,粘贴即可使用。
我们知道angular提供了ComponentFactoryResolver
抽象类,使用方法componentFactoryResolver.resolveComponentFactory()
可以动态的创建Component
export abstract class ComponentFactoryResolver {
static NULL: ComponentFactoryResolver = new _NullComponentFactoryResolver();
abstract resolveComponentFactory<T>(component: Type<T>): ComponentFactory<T>;
}
从源码可以看出,方法接收参数为component: Type<T>
。所以我们只需要传一个Component
类就可以动态创建组件了。这满足我们很多的使用场景,但是,对于开头我说的,我需要动态的template
模板,或者假设这里有一个textarea
输入框,往里边粘贴一段正确的Angular html
模板代码,然后可以自动动态编译模板展示对应效果。这样也是可以做到的,需要通过 Compiler 类来实现
class Compiler {
compileModuleSync<T>(moduleType: Type<T>): NgModuleFactory<T>
compileModuleAsync<T>(moduleType: Type<T>): Promise<NgModuleFactory<T>>
compileModuleAndAllComponentsSync<T>(moduleType: Type<T>): ModuleWithComponentFactories<T>
compileModuleAndAllComponentsAsync<T>(moduleType: Type<T>): Promise<ModuleWithComponentFactories<T>>
clearCache(): void
clearCacheFor(type: Type<any>)
}
从源码可以看出,Compiler
类中提供带有ompileModule-xxx
前缀的方法是可以实现动态编译NgModule
的,而第二、三个方法,可以实现编译Component。 下边我就举例使用 compileModuleAndAllComponentsSync
方法实现动态template模板动态创建Component
demo
代码演示
import {
Compiler, Component, NgModule, OnInit, ViewChild,
ViewContainerRef
} from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
@Component({
selector: 'my-app',
template: `<h1>Dynamic template:</h1>
<div #container></div>
<button (click)="dynamicTest()">click me to dymanic compile component</button>
`
})
export class AppComponent implements OnInit {
@ViewChild('container', { read: ViewContainerRef }) container: ViewContainerRef;
constructor(private compiler: Compiler) { }
ngOnInit() {
}
dynamicTest() {
this.addComponent(
`<h4 (click)="increaseCounter()">
Click to increase: {{counter}}
</h4>
`,
{
counter: 1,
increaseCounter: function () {
this.counter++;
}
}
);
}
private addComponent(template: string, properties: any = {}) {
@Component({ template })
class TemplateComponent { }
@NgModule({ declarations: [TemplateComponent] })
class TemplateModule { }
const mod = this.compiler.compileModuleAndAllComponentsSync(TemplateModule);
const factory = mod.componentFactories.find((comp) =>
comp.componentType === TemplateComponent
);
const component = this.container.createComponent(factory);
Object.assign(component.instance, properties);
// If properties are changed at a later stage, the change detection
// may need to be triggered manually:
// component.changeDetectorRef.detectChanges();
}
}
上边代码效果在线demo演示:dynamic-template-to-compile-dynamic-component-DEMO
总结
Angular 提供 ViewContainerRef
、TemplateRef
和 ComponentFactoryResolver
使得我们定制渲染和动态创建组件轻松实现。然后 Compiler
类的提供,使得满足一些特殊的场景。顿时感觉动态组件功能又强大的很多,官网文档对这些介绍都不多,只能自己找资料或者看源码摸索。
文章提到的 前端页面生成工具
工程为 ng-form-builder,写于本篇文章分享当天创建的工程,掐指一算,开发周期应该比较长,目前只有个人开发,也是工作不忙或者业余时间持续开发,总之会坚持到底,该工具会节约页面开发时间,去掉重复性的copy/paste
工作,提供效率。