这边文章主要介绍angular动态表单的实现思路。具体实现细节能够参考社区里semlinker的 动态建立表单这篇文章,以及他推荐的参考资源 Configurable Reactive Forms in Angular with dynamic components,笔者这篇文章主要是以上文章的部分翻译和思考。
有时候咱们须要一个灵活的表单,这个表单能够根据用户的选择,或者服务器返回的信息进行从新配置,好比:增长或删除一组input元素、一组select元素,等等。git
在这样的状况下,若是一开始就在模板里写下全部的表单,利用一个ngif树状结构进行选择控制,程序会变得比较冗余。github
这时。程序最好是可以根据用户的选择(driven by configuration)或者服务器的响应,自动生成所须要的表单。这就是动态表单要处理的业务。segmentfault
要动态生成表单,须要先理解组件是如何生成的。服务器
一个angular组件由两部分所组成。app
Wrapper可以与组件进行交互,当一个Wrapper初始化完成后,就已经帮咱们实例化了一个组件。同时,它也负责组件的change detection,以及触发钩子函数好比ngOnInit,ngOnChanges。dom
View负责呈现渲染事后的模板,将组件的外貌展现出来,而且可以触发Wrapper的change detection。一个组件能够有多个view,每个view能够经过调用angular提供的两个函数自行生成和销毁,这个过程不用顶层的视图参与。函数
一般状况下,咱们都是把组件内嵌到根组件或者另外一个组件当中使用。嵌入的组件称为子组件,被嵌入的称为父组件。这时,当咱们的子组件代码在被编译时,会生成一个组件工厂component factory(这是angular核心类ComponentFactory的一个实例),和一个hsot view,host view负责本组件在父组件视图内生成该组件的dom节点,以及生成该组件的wrapper和view。spa
而当咱们想要将一个动态组件插入某个组件视图时,则没法取得这个动态组件的实例,由于这些是非动态组件编译器作的事。翻译
angular提供了一些函数解决上面的难题,要使用这些函数咱们须要注入两个对象。code
constructor( private componentFactoryResolver: ComponentFactoryResolver, private viewcontainerRef: ViewContainerRef, ) { }
咱们注入了ComponentFactoryResolver,和ViewContainerRef。
ComponentFactoryResolver上提供了一个方法(resolveComponentFactory()),该方法接收一个组件类做为参数,生成一个基于该组件类的组件工厂,也就是咱们以前提到的那个组件工厂。
ViewContainerRef提供了一个方法(createComponent()),该方法接收组件工厂做为参数,在该视图中生成子组件。(我我的的理解是它处理了host view所作的事,为组件生成了wrapper和view)
上文简要的介绍了实现动态组件的一些技术,如今开始思考如何作一个动态表单。
咱们想要作出一个独立的动态表单模块,当咱们想要使用动态表单时,只需简单引入这个模块,稍加配置便可使用。
咱们但愿这个模块作好了后,在顶层使用者的角度会是这样一个工做流程:
咱们能够很容易的作出一个具备输入属性的组件,问题的核心在于这个组件是如何根据输入属性生成咱们想要的表单。
也就是说,是它本身调用ComponentFactoryResolver和ViewContainerRef进行组件的动态生成,仍是交给别人处理。
下图是实现思路:
这么处理的好处就是不须要由外层组件统一对各个拆分的动态组件进行管理,至关因而由动态组件本身进行管理。
外层组件容器大概会是下面这样:
<form> <ng-container *ngFor="let config of configs" [自定义指令] > </ng-container> </form>
configs是用户的配置数据,自定义指令寄宿在ng-container中,根据config渲染出各自的动态组件,而ng-container是透明的。
看一下代码目录结构,最后会是这个样子
以上就是大致的实现思路了,具体还有许多细节能够关注文章开头提到的那两篇文章,讲的很详细。