【问题标题】:angular material reactive forms pattern - how to make a component for this pattern using ControlValueAccessor角度材料反应形式模式 - 如何使用 ControlValueAccessor 为该模式制作组件
【发布时间】:2019-01-21 11:14:58
【问题描述】:

使用角材料mat-form-field 和反应形式。在一个项目中,我有一个看起来像这样的重复模式

// ts
this.formGroup = this.formBuilder.group({
    name: ['', ServerValidation]
})

<!-- html -->
<div [formGroup]="formGroup">
  <mat-form-field>
    <input
      matInput
      formControlName="name"
      [placeholder]="'Name'"
      name="name"
     />
    <mat-error
     *ngIf="
       formGroup
       .get('name')
       .hasError('serverValidation')
       "
      >
      {{
       formGroup
       .get("name")
       .getError("serverValidation")
      }}
     </mat-error>
   </mat-form-field>
</div>

这是一个高级别的 - 接受我可以从服务器接收验证错误 - 我如何在组件中重复这个 http 模板模式?我有一种预感,我应该使用 ControlValueAccessor - 但不知道该怎么做。

我想象的实现可能看起来像这样

<!-- html -->
<div [formGroup]="formGroup">
  <serverValidatedInput formControlName="'name'">
    <mat-error>error message for client side validation</mat-error>
  </serverValidatedInput>
</div>

所以本质上我想像使用常规材料输入(或多或少)一样使用这个自定义组件,除了它默认带有服务器验证错误。谁能在这里给我一些指导-谢谢。 :)

【问题讨论】:

    标签: angular angular-reactive-forms angular-forms angular-material-6 controlvalueaccessor


    【解决方案1】:

    有两种方法可以做到这一点 - 一种简单的方法和一种困难的方法。困难的方法是实现ControlValueAccessor,这为您在如何使用组件方面提供了更大的灵活性。简单的方法是通过您的组件将内容传递给内部的实际表单元素。如果您不需要灵活地使用此组件,请采用简单的方法。

    首先,您需要摆脱在mat-form-control 之外使用mat-error 的想法。它根本行不通,你也不需要它来工作。将其保留在表单字段中并为其提供内容。除此之外,将错误逻辑应用于mat-error 的内容,而不是mat-error 本身。请记住,您不需要逻辑来显示 mat-error - 当表单控件出现错误时,表单字段会自动处理。您只需要逻辑来确定错误 content 应该是什么。

    mat-form-field 的简单包装器如下所示:

    my-form-field.html

    <mat-form-field>
      <input matInput type="text" [placeholder]="placeholder" [formControl]="myFormControl" required>
      <mat-error>
        <ng-content></ng-content>
      </mat-error>
    </mat-form-field>
    

    my-form-field.ts

    import {Component, Input} from '@angular/core';
    import {FormControl} from '@angular/forms';
    
    @Component({
      selector: 'my-form-field',
      templateUrl: 'my-form-field.html'
    })
    export class MyFormField {
      @Input() myFormControl: FormControl;
      @Input() placeholder: string;
    }
    

    用法

    custom-form-field-example.html

    <form [formGroup]="formGroup">
      <my-form-field placeholder="Name" [myFormControl]="formGroup.get('name')">
        <ng-container *ngIf="formGroup.get('name').hasError('required')">
         This field is required
        </ng-container>
        <ng-container *ngIf="formGroup.get('name').hasError('serverValidation')">
          Server validation failed
        </ng-container>
      </my-form-field>
    </form>
    

    custom-form-field-example.ts

    import {Component} from '@angular/core';
    import {FormBuilder, FormGroup, Validators} from '@angular/forms';
    import {ServerValidation} from '...';
    
    @Component({
      selector: 'custom-form-field-example',
      templateUrl: 'custom-form-field-example.html'
    })
    export class CustomFormFieldExample {
      formGroup: FormGroup;
    
      constructor(formBuilder: FormBuilder) {
        this.formGroup = formBuilder.group({
          name: ['', [Validators.required, ServerValidation]]
        });
      }
    }
    

    【讨论】:

    • 不太清楚 - 找出你的 my-form-field.html 和我的示例之间的区别 - 在我的示例中,我将 &lt;mat-error&gt;formGroup.get(formControl).hasError('server-validation')&lt;/mat-error&gt; 融入其中 - 我想避免重写。
    • 我是在举一个例子,而不是最终的解决方案,展示如何使错误内容可重用。我希望您能够弄清楚将示例制作成适合您需求的解决方案所需的条件。将文本“服务器验证失败”替换为 {{formGroup.get('name').getError('serverValidation')}} 假设您的意思是 getError 而不是您所写的 hasError
    • 是的,我的 formGroup 未定义 - 抱歉花了这么长时间才解决这个问题 - 很忙 - 我正在尝试使用 controlValueAccessor atm 实现。
    • 我仍然没有管理它 - 但我发现这很有趣 - stackoverflow.com/a/44732530/8896573
    • 有更好的方法来做到这一点。将 NgControl 对象注入构造函数constructor(@Optional() @Self() public ngControl: NgControl) 并将实现ControlValueAccessor 的自定义组件分配为控件的访问器if (this.ngControl) this.ngControl.valueAccessor = this;。这将允许您使用任何类型的表单指令 - 反应式或模板、ngModelformControlformControlName。如果您尝试在组件中包装 MatInput 并希望它成为实际字段,则必须跳过更多的环节。
    猜你喜欢
    • 2021-07-08
    • 2022-11-25
    • 2021-11-25
    • 2020-04-26
    • 2020-05-19
    • 2019-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多