Angular 2:如何link 表单元素跨越一个动态创建的组件?

Angular 2: How to link form elements across a dynamically created components?

我在动态创建的组件中有一组表单域。 parent 组件拥有 form 标签。但是,none 个表单域正在添加到 Form。我正在使用 ComponentFactoryResolver 创建组件:

@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>

我怀疑它与注射器没有正确连接有关,但据我所知它被链接到 parent。我在 NgModel 中设置了一个断点,它为 parent 传递了一个空值,这就是问题所在。我将其追溯到看起来已编译的东西,它只是硬编码一个空值。所以我不确定它是如何用硬编码空值创建的。

关于如何解决这个问题有什么想法吗?

好的,事实证明它与该组件的动态特性无关。我删除了它并内联定义了我的所有组件,但它仍然有问题。问题是 Angular 不支持将表单控件嵌套在表单标签内的组件中。一旦你在一个组件中嵌套了一个表单控件,它就再也看不到 NgForm 了,这太疯狂了。

在网上阅读解决方案并发现没有人有好的解决方案后,我设计了 2 个自己的指令,将 Form 注册到 NgForm 的 DI 容器中,然后使用 DI 层次结构我可以将其注入另一个将执行以下注册的指令。

父组件模板:

<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>

一旦我准备好了这个,我就可以带回我的动态组件并且它工作得很好。真的很难到达那里。

它非常优雅和简单,不需要我像网络节目中的许多建议那样逐层传递表单实例。而注册一个表单控件无论是1层还是去掉999层的工作都是一样的

恕我直言,NgForm 和 NgModel 应该为我们开箱即用,但它们却没有,这会导致复杂的架构设计来完成中等高级的表单。