角度2:如何在动态创建的组件之间链接表单元素? [英] Angular 2: How to link form elements across a dynamically created components?

查看:64
本文介绍了角度2:如何在动态创建的组件之间链接表单元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在动态创建的组件中有一组表单字段.父组件拥有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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆