组件包装后如何标记formControl

时间:2019-06-07 15:02:14

标签: angular angular-material

我试图构建一个角度组件以包裹整个Angular Material的mat-form-field。

  <mat-form-field>
    <input matInput type="text" placeholder="{{ label }}" [(ngModel)]="_value"
           [required]="required" [disabled]="_disabled"
           (input)="intenrnalValueChange()" />
    <mat-hint>{{ hint }}</mat-hint>
    <mat-error>{{ getError() }}</mat-error>
  </mat-form-field>

该组件运行良好,但有一点麻烦。我无法将其标记为“感动”,我相信这是由于组件体系结构所致。我已经尝试了一些StackOverflow解决方案(和其他解决方案),这些解决方案在传统方式下效果很好,但不适用于我的组件。

    this.form.get('field').markAsTouched(); // should work
    this.form.markAsTouched(); // should not work
    this.form.markAllAsTouched(); // should work

我想标记一个按钮触摸过的字段,该按钮将显示所有仍然无效的字段(并通过错误提示其消息)。

我创建了一个简化的项目,可以在其中重现该问题。我希望单击按钮时该字段变为红色,并且消息显示在下面。不会发生,但是如果单击并模糊该字段,则会显示错误。

https://stackblitz.com/edit/angular-7mghym

问题是:如何更改我的项目(保留组件)以使按钮具有单击和模糊字段的相同效果?

1 个答案:

答案 0 :(得分:1)

您的方法有几个问题;

首先,您正在实现ControlValueAccessor,但是您的InputComponent有一个名为formControl的@Input。因此,当您将form.controls.field绑定到app-input时,您的表单不会与ControlValueAccessor进行交互。

<app-input label="Test" hint="It is a test" [formControl]="form.controls.field" required></app-input>

docs中所述;

  

ControlValueAccessor充当Angular表单API与DOM中的本机元素(html输入元素)之间的桥梁

第二个问题出现在这里; InputComponent中的DOM(html输入元素)和ControlValueAccessor之间的通信是通过ngModel处理的,而FormControl基本上是引擎盖下显式创建的form.controls.field的包装。

这些的结果; this.form.get('field').markAsTouched(); FormControl与ngModel实际的输入元素没有通信。因此,当您手动聚焦/模糊输入元素时,它会显示错误状态,但是ControlValueAccessor却什么也没做。

第三个问题是;即使您通过从@Input formControl中删除InputComponent使ngModel正常工作,并与没有mat-form-field的html输入进行通信;不过,input将无法与基础ControlValueAccessor元素进行交互(即获取错误状态),因为它需要实现MatFormFieldControl

第四个问题是,在使用ReactiveForms时,必须通过FormControl而不是隐式地处理验证(如您所需要的验证)和禁用状态。

好消息是,所有这些问题都有一个非常简单的解决方案,无需实施$request->get(),只需将formControl传递给InputComponent并将其绑定到html输入即可。

这是一个可行的例子; https://stackblitz.com/edit/angular-fwdrv9

希望对您有帮助,祝您有愉快的一天。