Angular 从中的自定义表单组件访问FormControl

Angular 从中的自定义表单组件访问FormControl,angular,angular-forms,Angular,Angular Forms,我的Angular应用程序中有一个自定义表单控件组件,它实现了ControlValueAccessor接口 但是,我想访问与我的组件关联的FormControl实例。我使用带有FormBuilder的被动表单,并使用formControlName属性提供表单控制 那么,如何从自定义表单组件内部访问FormControl实例呢?此解决方案诞生于Angular存储库中。请务必阅读,如果您对这个问题感兴趣,最好参与 我研究了FormControlName指令的代码,它启发我编写以下解决方案: @组件

我的Angular应用程序中有一个自定义表单控件组件,它实现了
ControlValueAccessor
接口

但是,我想访问与我的组件关联的
FormControl
实例。我使用带有
FormBuilder
的被动表单,并使用
formControlName
属性提供表单控制


那么,如何从自定义表单组件内部访问
FormControl
实例呢?

此解决方案诞生于Angular存储库中。请务必阅读,如果您对这个问题感兴趣,最好参与


我研究了
FormControlName
指令的代码,它启发我编写以下解决方案:

@组件({
选择器:“我的自定义表单组件”,
templateUrl:“./custom form component.html”,
供应商:[{
提供:NG_值访问器,
useExisting:CustomFormComponent,
多:真的
}]
})
导出类CustomFormComponent实现ControlValueAccessor,OnInit{
@Input()formControlName:字符串;
私人控制:抽象控制;
建造师(
@可选()@Host()@SkipSelf()
专用controlContainer:controlContainer
) {
}
恩戈尼尼特(){
if(this.controlContainer){
if(this.formControlName){
this.control=this.controlContainer.control.get(this.formControlName);
}否则{
console.warn('组件的主机元素缺少FormControlName指令');
}
}否则{
console.warn('找不到父FormGroup指令');
}
}
}
我将父
FormGroup
注入组件,然后使用通过
formControlName
绑定获得的控件名从组件中获取特定的
FormControl


但是,请注意,此解决方案是专门针对主机元素上使用
FormControlName
指令的用例定制的。它在其他情况下不起作用。为此,您需要添加一些额外的逻辑。如果您认为这应该由Angular解决,请确保访问。

因为@Ritesh已经在注释中写了,您可以将表单控件作为输入绑定传递:


然后,您可以在自定义表单组件中获得表单控件实例,如下所示:

@Input() control: FormControl;

通过
[formControl]
指令绑定时,使用
formControlName
作为输入参数不起作用

这是一个不需要任何输入参数就可以双向工作的解决方案

导出类MyComponent实现AfterViewInit{
私人控制:形式控制;
建造师(
专用注射器:注射器,
) { }
//表单控件仅在初始化后设置
ngAfterViewInit():void{
const ngControl:ngControl=this.injector.get(ngControl,null);
if(ngControl){
this.control=ngControl.control作为FormControl;
}否则{
//组件缺少表单控件绑定
}
}

}
基于前面的答案和在评论中找到的答案,以下是我认为基于
ControlValueAccessor的组件最干净的解决方案

// No FormControl is passed as input to MyComponent
<my-component formControlName="myField"></my-component>

以下是接受答案的简化/清理版本,适用于FormControlName和FormControl输入:

export class CustomFormComponent implements ControlValueAccessor, OnInit {

  @Input() formControl: FormControl;

  @Input() formControlName: string;

  // get ahold of FormControl instance no matter formControl or formControlName is given.
  // If formControlName is given, then controlContainer.control is the parent FormGroup/FormArray instance.
  get control() {
    return this.formControl || this.controlContainer.control.get(this.formControlName);
  }

  constructor(private controlContainer: ControlContainer) { }
}

您从何处获得此.control
?@DAG,如我在回答中所述:
我将父窗体组注入组件,然后使用通过formControlName绑定获得的控件名从组件中获取特定的FormControl。
@slavafomini:而不是注入父窗体组,然后使用formControllerName输入绑定,我们不能将form控件作为输入绑定传递吗?我有一个类似的要求,我想从自定义表单组件访问表单控件,并将该表单控件作为输入绑定传递给自定义表单组件。对此印象深刻的任何人都应该看看这里,IMO发送该控件违背了回答的目的。当然,你可以发送控件并用它做任何事情。。。(从这个答案中,您不需要在ctor中输入任何内容)。问题的实质是问如何从内部访问您正在定制的控件。这应该是可行的。这个解决方案肯定比公认的答案好。虽然这个解决方案对我也很有效,而且看起来比公认的解决方案优雅得多,在Angular 7中,我得到了这个tslint错误:
get不推荐使用:从v4.0.0使用Type或InjectionToken
将此解决方案调整为使用InjectionToken应该很容易。Try
const ngControl=this.injector.get(ngControl作为Type)
@Randy当
[formControl]=“form.get('data')中的控件数据为时,情况如何
被删除并再次添加?我认为我们最终将引用第一个数据控件,而不是我们表单中的当前数据控件。这是一个不错的解决方案。您可能需要删除
在组件声明中提供:NG_VALUE_ACCESSOR
,以防止循环依赖。请参阅: