将 formControlName 传递给 Angular 组件

Posted

技术标签:

【中文标题】将 formControlName 传递给 Angular 组件【英文标题】:Passing formControlName into Angular component 【发布时间】:2019-10-28 01:43:28 【问题描述】:

我有一个反应形式。设置与此类似:

myForm: FormGroup;

    this.myForm= new FormGroup(
        name: new FormControl("", [Validators.required, Validators.maxLength(15), Validators.pattern('...')]),
        ...
    );

我在我的表单上这样使用它:

  <input
    type="text"
    formControlName="name"
  />
  <div *ngIf="name.errors?.required">
      Name is required
  </div>
  <div *ngIf="name.errors?.maxlength">
      Name must be  name.errors.maxlength.requiredLength  characters        
  </div>
  <div *ngIf="name.errors?.pattern">
      Name has invalid characters.
  </div>

这只是我的表格的精简版。我有多个输入,我必须为每个输入创建错误 div。

为了解决这个问题,我尝试创建一个组件。该组件与上面的代码非常相似:

  <input
    type="text"
    [formControlName]="formControlName"
  />
  <div *ngIf="name.errors?.required">
      Name is required
  </div>
  etc...

ts 文件:

@Component(
  selector: 'app-text',
  templateUrl: './text.component.html'
)
export class TextComponent  

  @Input() formControlName: FormControl;

所以在我的表单上,我想按如下方式使用这个组件:

<app-text [formControlName]="name"></app-text>

但我无法让它与 formControlName 属性一起使用。

这可能吗?

谢谢

我快到了。

我已经创建了这个 StackBlitz,所以请展示我的进度:

Demo

现在只是在努力解决错误以及如何访问 formControl 以检查这些错误

【问题讨论】:

为什么要在 TextComponent 中使用 formControl? 所以我可以使用验证器来显示组件中的错误,从而不会在任何地方重复它们 你能提供stackblitz吗? 您需要为此使用自定义值访问器。如果你想避免使用样板,你可以使用github.com/cloudnc/ngx-sub-form在这里查看类似的帖子***.com/questions/40806779/… @maxime1992,不,如果您不想创建自定义表单控件,则不需要使用值访问器。只要通过控制 【参考方案1】:

您需要将表单控件传递给输入元素,

  <input

    [value]="val"
    type="text"
    (input)="val=$event.target.value;onChange($event.target.value)"
    (blur)="onTouched()"
    [formControl]="control"

  >


  <span *ngIf="control && !control.valid && control.touched">
    <span class="error" *ngIf="control.errors['required']"> The field should not be empty</span>
    <span class="error" *ngIf="control.errors['email']"> The field should be an email 
    </span>
  </span>

获取自定义组件中的控件作为输入,并据此显示错误。

import  Component, OnInit, forwardRef, Input, OnChanges  from '@angular/core';
import  FormControl, ControlValueAccessor, NG_VALUE_ACCESSOR, NG_VALIDATORS  from '@angular/forms';

@Component(
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.css'],
  providers: [
     provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TestComponent), multi: true 
  ]
)
export class TestComponent implements ControlValueAccessor, OnChanges 

  constructor()  

  propagateChange:any = () => ;

   @Input() control: FormControl;
 @Input('messageValue') _messageValue = 'whateves';  

  get messageValue() 
    return this._messageValue;
  

  set messageValue(val) 
    console.log('set messageValue', val)
    this._messageValue = val;
    this.propagateChange(val);
  

hi(event) 
  console.log('hi');
  console.log(event)
  this.messageValue = event;

  ngOnInit() 
  

  ngOnChanges(changes) 
    console.log('changes', changes);
    this.propagateChange(this.messageValue);
  

    writeValue(value) 
      console.log('writeValue', value);
          if (value) 
            this.messageValue = value;
      
    


  registerOnChange(fn) 
    console.log('onChange')
    this.propagateChange = fn;
  

  registerOnTouched() 


【讨论】:

您不需要从 DefaultValueAccesor 扩展,也不需要提供 NG_VALUE_ACCESOR。如果你使用[formControl]="control" 并且在父级中你作为输入传递&lt;app-text [control]="myControl.get('name')"&gt;&lt;/app-text&gt; 是可以的 好的,我几乎可以完成这项工作,但我仍在努力解决错误部分。如何访问 formControl 以检查错误?我尝试了您的解决方案,但没有奏效。看到这个stackblitz.com/edit/… 如果解决方案解决了您的问题,您可以接受这个作为答案。【参考方案2】:

如果您想访问formControl,最好使用NgControl 作为 DI

推理:

NgModel FormControlDirective FormControlName

都是NgControl 的子类,所以如果你这样做,你将为自己提供很大的帮助,这样如果你改变主意使用 formControl 到 NgControl 等......你会已经使用NgControl覆盖了这些基础

所以举个例子,它看起来像

import  Component, OnInit, Self  from '@angular/core';

import  NgControl  from '@angular/forms';

@Component(
  selector: 'app-text',
  templateUrl: './text-box.component.html',
  styleUrls: ['./text-box.component.css']
)
export class TextBoxComponent implements OnInit 

  constructor(@Self() private ngControl: NgControl)  

  ngOnInit() 
    console.log(this.ngControl);
  


HTML

<app-text[formControl]="control"></app-text>

我们使用@Self 的原因是组件不会在注入器树上进一步查找ngControl,而只是在它的元素上查找。所以你可以嵌套等......

这对指令也非常有益,但到目前为止我希望这会有所帮助!

【讨论】:

如何在父级中设置formControlName?

以上是关于将 formControlName 传递给 Angular 组件的主要内容,如果未能解决你的问题,请参考以下文章

在表单组中动态创建formcontrolname

使用 formControlName 和 ngModel 的角度 6 警告

在 Angular 中动态创建控件时不呈现 formControlName

带有 ControlValueAccessor 和 formControlName 的 Angular Material Datepicker [重复]

在Angular2中将管道添加到formControlName

以角度与 FormControlName 绑定