Javascript Angular2:将表单上下文绑定到ngTemplateOutlet

Javascript Angular2:将表单上下文绑定到ngTemplateOutlet,javascript,angular,typescript,Javascript,Angular,Typescript,我试图定义一个包含动态表单(使用ReactiveForms)的组件,用户应该能够在其中添加/删除控件。 控件可以采用多种形式,并且必须在组件外部定义,因此我认为TemplateRef最适合于此 我正在努力找到一种方法,通过使用formControlName将外部定义的控件绑定到内部表单 以下是实施的开始: // expandable.component.ts [...] @Component({ selector: 'expandable', templateUrl: 'app/com

我试图定义一个包含动态表单(使用ReactiveForms)的组件,用户应该能够在其中添加/删除控件。 控件可以采用多种形式,并且必须在组件外部定义,因此我认为TemplateRef最适合于此

我正在努力找到一种方法,通过使用formControlName将外部定义的控件绑定到内部表单

以下是实施的开始:

// expandable.component.ts

[...]
@Component({
  selector: 'expandable',
  templateUrl: 'app/component/common/expandable/expandable.component.html',
  styleUrls: ['app/component/common/expandable/expandable.component.css']
})
export class ExpandableComponent {
  @ContentChild('childTemplate') childTemplate: TemplateRef<any>;

  @Input() children: Array<any>;
  public form: FormGroup;

  constructor(private _changeDetector: ChangeDetectorRef,
              private _formBuilder: FormBuilder) {
    this.children = [];
  }

  public ngOnInit(): void {
    this.form = this._formBuilder.group({
      children: this._formBuilder.array([])
    });

    const arrayControl = <FormArray>this.form.controls['children'];
    this.children.forEach(child => {
      const group = this.initChildForm();
      arrayControl.push(group);
    });
  }

  private initChildForm(): AbstractControl {
    return this._formBuilder.group({
      key: ['Initial Key', [Validators.required]],
      value: ['Initial Value', [Validators.required]]
    });
  }

  public addChild(): void {
    const control = <FormArray>this.form.controls['children'];
    control.push(this.initChildForm());
    this._changeDetector.detectChanges();
  }
}
//expandable.component.ts
[...]
@组成部分({
选择器:“可扩展”,
templateUrl:'app/component/common/expandable/expandable.component.html',
样式URL:['app/component/common/expandable/expandable.component.css']
})
导出类可扩展组件{
@ContentChild('childTemplate')childTemplate:TemplateRef;
@Input()子项:数组;
公共形式:FormGroup;
构造函数(私有_changeDetector:ChangeDetectorRef,
私有_formBuilder:formBuilder){
这是:children=[];
}
public ngOnInit():void{
this.form=this.\u formBuilder.group({
子项:this.\u formBuilder.array([])
});
const arrayControl=this.form.controls['children'];
this.children.forEach(child=>{
const group=this.initChildForm();
arrayControl.push(组);
});
}
私有initChildForm():AbstractControl{
返回此。\u formBuilder.group({
密钥:[‘初始密钥’,[Validators.required]],
值:[‘初始值’,[Validators.required]]
});
}
public addChild():void{
const control=this.form.controls['children'];
control.push(this.initChildForm());
这是._changeDetector.detectChanges();
}
}
-


添加子项
尝试从外部定义模板的名称:

  <expandable>
    <template #childTemplate>
      <input class="form-control" 
        formControlName="value" />
      </template>
  </expandable>

我天真地试图将formControlName绑定到外部隐式传递的上下文,但没有成功,因为我得到了“找不到名为:‘value’的控件”。理想情况下,我希望能够将formControlName绑定到
expandable.component.html
中,但我也看不到这样做的方法

对此有何想法?

是的,这是可能的:

您需要实现
ControlValueAccessor
接口,该接口
ngModel
formControlName
注入,如下所示:

@Directive({
  selector: 'control',
  providers: [
    {provide: NG_VALUE_ACCESSOR, multi: true, useExisting: SwitchControlComponent}
  ]
})
export class SwitchControlComponent implements ControlValueAccessor {
  isOn: boolean;
  _onChange: (value: any) => void;

  writeValue(value: any) {
    this.isOn = !!value;
  }

  registerOnChange(fn: (value: any) => void) {
    this._onChange = fn;
  }

  registerOnTouched() {}

  toggle(isOn: boolean) {
    this.isOn = isOn;
    this._onChange(isOn);
  }
}
html:

  <expandable>
    <template #childTemplate>
      <div [formGroup]="form">
         <input control class="form-control" 
           formControlName="value" />
         </template>
      </div>
  </expandable>

进一步阅读:

  <expandable>
    <template #childTemplate>
      <div [formGroup]="form">
         <input control class="form-control" 
           formControlName="value" />
         </template>
      </div>
  </expandable>