角度2:如何在动态创建的组件之间链接表单元素? [英] Angular 2: How to link form elements across a dynamically created components?
问题描述
我在动态创建的组件中有一组表单字段.父组件拥有form
标记.但是,没有一个表单字段被添加到Form
中.我正在使用ComponentFactoryResolver
创建组件:
I have a set of form fields that are in a dynamically created component. The parent Component owns the form
tag. However, none of the form fields are being added to the Form
. I'm using the ComponentFactoryResolver
to create the component:
@Component({
selector: 'fieldset-container',
templateUrl: './fieldset-container.component.html',
styleUrls: ['./fieldset-container.component.scss'],
entryComponents: ALL_FIELD_SETS,
})
export class FieldsetContainerComponent<C> {
fieldsetComponent : ComponentRef<any> = null;
@Input() formGroup : FormGroup;
@ViewChild('fieldSetContainer', {read: ViewContainerRef})
fieldsetContainer : ViewContainerRef;
@Output() onComponentCreation = new EventEmitter<ComponentRef<any>>();
constructor(private resolver : ComponentFactoryResolver) {
}
@Input() set fieldset( fieldset : {component : any, resolve : any }) {
if( !fieldset ) return; // sorry not right
// Inputs need to be in the following format to be resolved properly
let inputProviders = Object.keys(fieldset.resolve).map((resolveName) => {return {provide: resolveName, useValue: fieldset.resolve[resolveName]};});
let resolvedInputs = ReflectiveInjector.resolve(inputProviders);
// We create an injector out of the data we want to pass down and this components injector
let injector = ReflectiveInjector.fromResolvedProviders(resolvedInputs, this.fieldsetContainer.parentInjector);
// We create a factory out of the component we want to create
let factory = this.resolver.resolveComponentFactory(findComponentForFieldset(fieldset.component));
// We create the component using the factory and the injector
let component : ComponentRef<any> = factory.create(injector);
// We insert the component into the dom container
this.fieldsetContainer.insert(component.hostView);
// Destroy the previously created component
if (this.fieldsetComponent) {
this.fieldsetComponent.destroy();
}
this.fieldsetComponent = component;
this.onComponentCreation.emit( this.fieldsetComponent );
}
}
模板:
<div #fieldSetContainer [formGroup]="formGroup"></div>
动态组件的用法:
<form class="form" #omaForm="ngForm">
<div *ngFor="let fieldset of page?.fieldsets">
<fieldset-container [fieldset]="{ component: fieldset, resolve: {} }" (onComponentCreation)="onComponentCreation($event)" [formGroup]="omaForm.form"></fieldset-container>
</div>
</form>
我怀疑这与注入器未正确连接有关,但据我所知,它已链接到父代.我已经在NgModel中设置了一个断点,并且为父级传递了一个null,这就是问题所在.我将其追溯到看起来已编译的东西中,并且很难对null进行编码.因此,我不确定是如何在其中使用硬编码的null来创建的.
I suspect it has something to do with the injector not being hooked up correctly, but from what I can tell it is chained to the parent. I've set a breakpoint in NgModel and it is passed a null for parent which is the problem. I traced that back up into something that looks compiled and it was just hard coding a null. So I'm not sure how that was created with hard coded nulls in there.
关于如何解决此问题的任何想法?
Any ideas on how to fix this?
推荐答案
好吧,事实证明它与该组件的动态特性无关.我删除了它,并内联定义了所有组件,但仍然有问题.问题在于,Angular不支持开箱即用的嵌套在form标签内的组件内部的表单控件.将表单控件嵌套在组件中后,就再也看不到NgForm了,这很疯狂.
Ok it turns out it has nothing to do with the dynamic nature of this component. I removed it and defined all of my components inline and it still had the problem. The issue was that having form controls inside a Component that were nested within a form tag is just not supported by Angular out of the box. Once you nest a form control in a component it can't see the NgForm anymore which is crazy.
在网络上阅读解决方案并发现没有人有好的解决方案后,我设计了自己的2条指令,这些指令将Form注册到NgForm的DI容器中,然后使用DI层次结构将其注入到另一个将在下面执行注册.
After reading solutions on the web and seeing that no one had a good solution I designed 2 of my own directives that registered the Form into the DI container up at the NgForm, then using DI hierarchy I could inject that into another Directive that would perform the registration below.
父组件模板:
<form nested>
<my-component .../>
</form>
子组件模板:
<div>
<input name="street" [(ngModel)]="address.street" required nest/>
<input name="city" [(ngModel)]="address.city" required nest/>
<input name="state" [(ngModel)]="address.state" required nest/>
<input name="zip" [(ngModel)]="address.zip" required nest/>
</div>
一旦我准备好了这个,就可以恢复我的动态组件,并且它可以完美地工作.真的很难到达那里.
Once I had this in place then I could bring back my dynamic component and it worked perfectly. It was just really hard to get there.
这真的很优雅,很简单,不需要像网络上的许多建议一样,将表单实例向下传递到各个图层.注册表单控件(无论是删除1层还是删除999层)的工作是相同的.
It's really elegant and simple and doesn't require me to pass the form instance down through the layers like so many suggestions on the web show. And the work to register a form control whether it's 1 layer or 999 layers removed is the same.
恕我直言,NHOForm和NgModel应该为我们开箱即用,但它们不这样做,这会导致复杂的体系结构设计来完成适度高级的表单.
IMHO NgForm and NgModel should just do this out of the box for us, but they don't which leads to complicated architecture design to accomplish moderately advanced forms.
这篇关于角度2:如何在动态创建的组件之间链接表单元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!