2016-10-24 32 views
2

我已经创建了一些定制组件,其中的每一个实现ControlValueAccessor,以便它们可以作为FormGroup内控制功能内注册一个动态添加定制组件的一种形式的控制。通常,唯一要做的事情就是将formControlName指令添加到HTML中的每个自定义组件。如何将formgroup

不过,我在运行时使用this技术附加这些部件的形式。

我的问题是,我不能注册这些组件与包含FormGroup因为我不能声明formControlName指令(或任何指令,对于这一点)与动态添加控制。

有其他人发现了如何这可能是可能的吗?目前,我正在包装的另一个组件内的每个控制,这样我就可以使用formControlName指令,但是这仅仅是太丑陋和劳动密集型的。


下面是什么,我已经作为一个独立的应用程序Angular2,这说明了一个组件(CustomComponent)实现在启动时被编程添加一个精简的例子。为了绑定CustomComponentFormGroup,我已经创造CustomContainerComponent我宁愿避免。

import { 
    Component, ReflectiveInjector, ViewContainerRef, Compiler, NgModule, ModuleWithComponentFactories, 
    OnInit, ViewChild, forwardRef 
} from '@angular/core'; 
import {BrowserModule} from '@angular/platform-browser'; 
import {NG_VALUE_ACCESSOR, ControlValueAccessor, FormGroup, FormBuilder, ReactiveFormsModule} from '@angular/forms'; 


export class AbstractValueAccessor<T> implements ControlValueAccessor { 
    _value: T; 
    get value(): T { 
    return this._value; 
    }; 

    set value(v: T) { 
    if (v !== this._value) { 
     this._value = v; 
     this.onChange(v); 
    } 
    } 

    writeValue(value: T) { 
    this._value = value; 
    this.onChange(value); 
    } 

    onChange = (_) => {}; 
    onTouched =() => {}; 

    registerOnChange(fn: (_: any) => void): void { 
    this.onChange = fn; 
    } 

    registerOnTouched(fn:() => void): void { 
    this.onTouched = fn; 
    } 

} 

export function MakeProvider(type: any) { 
    return { 
    provide: NG_VALUE_ACCESSOR, 
    useExisting: forwardRef(() => type), 
    multi: true 
    }; 
} 

@Component({ 
    selector: 'app-custom', 
    template: `<input type="text" [value]="value">`, 
    providers: [MakeProvider(CustomComponent)] 
}) 
class CustomComponent extends AbstractValueAccessor<string> { 

} 

@Component({ 
    selector: 'app-custom-container', 
    template: `<div [formGroup]="formGroup"><app-custom formControlName="comp"></app-custom></div>` 
}) 
class CustomContainerComponent { 
    formGroup: FormGroup; 
} 

@NgModule({ 
    imports: [BrowserModule, ReactiveFormsModule], 
    declarations: [CustomComponent, CustomContainerComponent] 
}) 
class DynamicModule { 
} 

@Component({ 
    selector: 'app-root', 
    template: `<h4>Dynamic Components</h4><br> 
      <form [formGroup]="formGroup"> 
       <div #dynamicContentPlaceholder></div> 
      </form>` 
}) 
export class AppComponent implements OnInit { 

    @ViewChild('dynamicContentPlaceholder', {read: ViewContainerRef}) 
    public readonly vcRef: ViewContainerRef; 

    factory: ModuleWithComponentFactories<DynamicModule>; 
    formGroup: FormGroup; 

    constructor(private compiler: Compiler, private formBuilder: FormBuilder) { 
    } 

    ngOnInit() { 
    this.compiler.compileModuleAndAllComponentsAsync(DynamicModule) 
     .then((moduleWithComponentFactories: ModuleWithComponentFactories<DynamicModule>) => { 
     this.factory = moduleWithComponentFactories; 
     const compFactory = this.factory.componentFactories.find(x => x.selector === 'app-custom-container'); 
     const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector); 
     let cmp = this.vcRef.createComponent(compFactory, this.vcRef.length, injector, []); 
     (<CustomContainerComponent>cmp.instance).formGroup = this.formGroup; 
     }); 

    this.formGroup = this.formBuilder.group({ 
     'comp': ['hello world'] 
    }) 
    } 
} 

@NgModule({ 
    imports: [BrowserModule, ReactiveFormsModule], 
    declarations: [AppComponent], 
    bootstrap: [AppComponent] 
}) 
export class AppModule { 
} 
+1

无代码无哭...添加你在这里尝试 – smnbbrv

+1

你是非常正确的。我会添加一些代码 –

+0

感谢您的更新。动态创建组件的最终用途是什么?你想只有动态控件的动态表单,或者你想有一个一个地使用控件的能力吗? – smnbbrv

回答

2

如果我没有误解你的需求...

奇怪的是,您将您的表单组的AppComponent内。相反,您可以动态创建完整的表单。为了做到这一点,你需要实现两个功能:

  1. 一个产生从JSON配置模板
  2. 另外一个产生从JSON配置形式

然后,只需建立一个大单包含所有输入的容器组件。我会建议在这里使用服务:

@Injectable() 
export class ModuleFactory { 

    public createComponent(jsonConfig: SomeInterface) { 
    @Component({ 
     template: ` 
     <div ngForm="form">${ /* and here generate the template containing all inputs */ }</div> 
     ` 
    }) 
    class FormContainerComponent { 
     public form: FormGroup = /* generate a form here */; 
    }; 

    return FormContainerComponent; 
    } 

    public createModule(component: any) { 
    @NgModule({ 
     imports: [ 
     CommonModule, 
     ReactiveFormsModule 
     ], 
     declarations: [ component ] 
    }) 
    class MyModule {}; 

    return MyModule; 
    } 

} 

这当然只是一个简化版本,但它工作正常,我不是只对纯形式,但对嵌套表格组/阵列/控制项目。

一旦注入服务,您可以使用这两个函数生成模块和组件。

+1

这实际上工作得很好。非常感谢您的时间。 –