【问题标题】:How to implement Reactive Form as custom component using NG_VALUE_ACCESSOR?如何使用 NG_VALUE_ACCESSOR 将 Reactive Form 实现为自定义组件?
【发布时间】:2019-06-13 08:08:58
【问题描述】:

我确实有一个用于模板驱动表单的自定义组件,我使用NG_VALUE_ACCESSOR。它真的很好用。现在我想切换到反应形式。 StackBlitz Demo

问题在于如何使用响应式表单作为自定义组件并通过 formGroupformControlName 以及如何将其余其他属性动态传递给父组件,例如 required 等。

据我所知,required 属性是在*.component.ts 文件中定义的。因此,不可能像在模板驱动表单中那样在父级中动态设置属性绑定。

我一直在搜索,但遗憾的是没有明显的结果。

知道如何使用NG_VALUE_ACCESSOR 将响应式表单实现为自定义组件并动态传递属性吗?

【问题讨论】:

    标签: angular angular-reactive-forms


    【解决方案1】:

    我真的不知道你想要什么。您的自定义表单控件也适用于响应式表单(请参阅 your custom form control using reactive form

    <form [formGroup]="myForm">
       <app-elements-input formControlName="name" ...>
       </app-elements-input>
    </form>
    //and 
    myForm=new FormGroup(
        {
            name:new FormControl()
        }
      )
    

    嗯,有时需要知道控件何时无效,触摸...

    一种简单的方法是添加为提供者 NG_VALIDATORS

    {provide: NG_VALIDATORS,
          useExisting:forwardRef(() => InputComponent), 
           multi: true} 
    

    添加一个变量,例如

    control:any=null;
    

    e 实现了 Validator,它在声明中添加并创建一个函数 validate 我们为“控制”赋予价值

    export class InputComponent implements ...,Validator {..}
    
    public validate(c: FormControl) {
      if (!this.control)
        this.control=c;
      return null;
     // return (!this._value && !this.required)?{required:true}:null
    }
    

    所以你可以在 html 中使用一些类似的东西

    <span *ngIf="control?.invalid">*</span>
    

    不要忘记在控件被触摸时指示,在示例中,我们可以使用输入的事件(模糊)

    <input ... (blur)="onTouched()">
    

    如果你想制作一个组件来控制一个表单组,它只能作为 `@Input()' fromGroup 或 formControl 传递

    <form [formGroup]="myForm">
           <children [argformControl]="myForm.get('name')">
           </children>
    </form>
    //and
    @Input() argformControl:FormControl
    

    <form [formGroup]="myForm">
           <children [argFormGroup]="myForm">
           </children>
    </form>
    //and
    @Input() argFormGroup:FormGroup
    

    Update 这允许,例如如果我们有一个对象数组,比如

    data=[{name:'name',label:'Name'},{name:'surname',label:'Surname'}]
    

    点赞

    <!--I add a "clasic" *ngIf to avoid initialize problems
       It can be placed in the form, or in children-->
    <form *ngIf="myForm" [formGroup]="myForm">
       <children [argFormGroup]="myForm" [data]="data">
       </children>
    </form>
    

    我们的孩子变成了

    <div *ngFor="let item of data">
    {{item.label}}<input [formControl]="argFormGroup.get(item.name)">
    </div>
    //and 
     @Input() argFormGroup:FormGroup
     @Input() data:any[]
    

    自定义 formControl 是一个“黑匣子”。您发送一个值 - 一个字符串,一个对象...... - 您可以修改此字符串或对象。它看起来像一个“复杂的输入”(一个 mat-date-picker,例如是一个自定义表单控件)

    【讨论】:

    • 谢谢。但我想我错过了在父组件中使用多个输入文本的情况。因此,假设我确实有两个具有两个不同名称的文本字段。 2 个不同的名称属性如何工作?这个概念背后的想法是能够根据需要嵌入许多输入字段并传递不同的名称。而且我不需要对*.component.ts 文件进行任何更改。我认为formControlName="name" 应该是动态的。
    • 我更新了我的答案。关键是使用 [formControl],而不是 [formControlName]
    • 不幸的是仍然无法正常工作。当我使用 2 个不同的名称添加两次输入时,例如&lt;app-elements-input [type]="'text'" formControl="name"....&gt;&lt;/app-elements-input&gt;&lt;br&gt;&lt;app-elements-input [type]="'text'" formControl="name2"....&gt;&lt;/app-elements-input&gt;。控制台抛出:ERROR TypeError: Cannot create property 'validator' on string 'name'ERROR TypeError: Cannot create property 'validator' on string 'name2'。我一直在您的 StackBlitz Demo 上对其进行测试。
    • @k.vincent,你说得对,我们需要放一个 *ngIf 以避免初始化问题 - 存在“数据”,但不存在 myForm2。所以,&lt;form *ngIf="myForm2" [formGroup]="myForm2"&gt;。我刚刚更新了stackblitz。 -另一种方法是在儿童中使用&lt;ng-container *ngIf="argFormGroup"&gt;....&lt;/ng-container&gt;
    • 再次感谢。仍然没有。我想让这部分 name:new FormControl('',Validators.required), surname:new FormControl('',Validators.required) 动态化。我不想触摸app.component.ts 来添加额外的formControlName,并且如果我需要在TS 文件中将&lt;children [argFormGroup]="myForm2" [data]="data" required="true"&gt; &lt;/children&gt; 强制归档,则应该在视图中定义required 属性。
    猜你喜欢
    • 1970-01-01
    • 2016-07-27
    • 2019-01-23
    • 1970-01-01
    • 2020-06-17
    • 2021-10-14
    • 1970-01-01
    • 1970-01-01
    • 2023-01-18
    相关资源
    最近更新 更多