2017-04-13 70 views
1

我有一组表单域在动态创建的组件中。父组件拥有form标记。但是,没有任何表单域被添加到Form。我使用的是ComponentFactoryResolver创建组件:Angular 2:如何在动态创建的组件中链接表单元素?

@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作为parent的问题。我将它追溯到看起来编译的东西,而且只是编写了一个空值。所以我不确定那里是如何用硬编码的零点创建的。

有关如何解决此问题的任何想法?

+0

我认为我们需要工作示例来重现请创建一个plunker。 – yurzui

回答

1

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

在网络上阅读解决方案并看到没有人有一个好的解决方案后,我设计了2条我自己的指令,将表单注册到DI容器中的NgForm中,然后使用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应该为我们开箱即用,但它们不会导致复杂的架构设计来实现中等先进的形式。

相关问题