Angular 2:如何在动态创建的组件之间链接表单元素?



我有一组表单字段,这些表单字段位于动态创建的组件中。 父组件拥有form标记。 但是,不会将任何表单域添加到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>

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

关于如何解决这个问题的任何想法?

好吧,事实证明它与此组件的动态性质无关。 我删除了它并内联定义了我的所有组件,但它仍然存在问题。 问题是,Angular 开箱即用地不支持在组件中嵌套在表单标记中的表单控件。 一旦您将表单控件嵌套在组件中,它就无法再看到NgForm,这太疯狂了。

在阅读了网络上的解决方案并看到没有人有好的解决方案后,我设计了 2 个我自己的指令,将表单注册到 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 应该为我们开箱即用,但它们没有,这会导致复杂的架构设计来完成中等高级的形式。

最新更新