【问题标题】:<mat-error> not working inside ControlValueAccessor when inheriting validations from custom formControl in parent component从父组件中的自定义 formControl 继承验证时,<mat-error> 在 ControlValueAccessor 中不起作用
【发布时间】:2020-04-28 19:12:10
【问题描述】:

子 ControlValueAccessor 组件中的&lt;mat-error&gt; 对父 formControl 验证无效。

<!-- Parent component template -->
<app-unique-name-text-box [formControl]="categoryName"></app-unique-name-text-box>
// Parent Component ts
this.addCategoryForm = fb.group({
      'categoryName': ['', Validators.compose([Validators.required, BlankSpaceValidator.validate])]
});
this.categoryName = this.addCategoryForm.controls['categoryName'];
<!-- Child component template -->
<mat-form-field class="example-full-width">
    <input matInput placeholder="Name" [formControl]="uniqueNameControl" (blur)="onInputBlur()">
    <mat-error *ngIf="errorState">Enter a unique name</mat-error>
</mat-form-field>
// Child component ts
import {Component, OnInit, Optional, Self} from '@angular/core';
import {ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, NgControl} from '@angular/forms';
import {distinctUntilChanged} from "rxjs/operators";

@Component({
  selector: 'app-unique-name-text-box',
  templateUrl: './unique-name-text-box.component.html',
  styleUrls: ['./unique-name-text-box.component.scss']
})
export class UniqueNameTextBoxComponent implements OnInit, ControlValueAccessor {
  uniqueNameControl: FormControl = new FormControl('');

  onChanged: any = () => {};
  onTouched: any = () => {};

  constructor(@Optional() @Self() public ngControl: NgControl) {
    if (this.ngControl != null) {
      this.ngControl.valueAccessor = this;
    }
    this.uniqueNameControl.valueChanges.pipe(distinctUntilChanged()).subscribe(
      val => this.setInputValue(val)
    );
  }

  get errorState() {
    return this.ngControl.errors !== null && !!this.ngControl.touched;
  }

  ngOnInit() {
  }

  registerOnChange(fn: any): void {
    this.onChanged = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }

  writeValue(obj: any = ''): void {
    this.uniqueNameControl.patchValue(obj);
  }

  setInputValue(val = '') {
    this.uniqueNameControl.patchValue(val);
    this.onChanged(val);
  }
}

我是否需要在此处添加一些额外的配置以使 &lt;mat-error&gt; 在父 formControl 上显示无效

【问题讨论】:

  • 如果您的子组件没有向providers 注册,则它不是控制值访问器。 Google for "ControlValueAccessor example" 查找示例,并在 Component 装饰器中查找 providers 声明。
  • 我正在遵循这种方法:material.angular.io/guide/…,否则我会得到cyclic dependency error
  • 我认为更好的方法是使用自定义的errorStateMatcher。这个想法是,如果 ngControl 不正确,则内部 mat-input 不正确,请参阅stackoverflow.com/questions/58459617/…。注意:在stackblitz中我添加了一个@Input错误来控制formGroup的错误
  • @GeniusGo 来自您共享的链接。它实际上只是说'如果需要直接访问控件 - 从提供者那里删除 ref 转发'

标签: angular angular-material controlvalueaccessor


【解决方案1】:
  ngAfterContentInit() {
    // Subscribe to changes in the child control state in order to update the form field UI.
    this.stateChanges.subscribe(() => {
      return (this.errorState = !this.ngControl.control.valid);
    });   }

【讨论】:

  • 请在您的回答中添加描述
  • 很高兴提供可以解决问题的代码。但是您还应该提供一个平淡无奇的描述,解释为什么它可以解决问题。一个简单的描述就足够了。
  • 虽然此代码可以解决问题,including an explanation 说明如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提出问题的人。请edit您的答案以添加解释并说明适用的限制和假设。 From Review
【解决方案2】:

您必须像这样手动将父控件验证器添加到子组件

试试这个:

 ngOnInit() {
    const validators = this.ngControl.control.validator;
    this.uniqueNameControl.setValidators(validators ? validators : null);
    this.uniqueNameControl.updateValueAndValidity();
 }

Example

【讨论】:

  • 哦..所以,我实际上并没有通过ngControl 继承验证? :P
  • 在您的子组件中,您正在创建新的 FormControl,默认情况下它没有任何验证器。所以它是覆盖父表单控件验证器。
  • 好的。对于setErrors(),为什么我需要在this.uniqueNameControl.updateValueAndValidity(); 之后对其设置继承错误。如果我不这样做,它就行不通。从父 formControl 继承验证器和错误是否正确?
  • 当您动态添加验证器时,您必须手动调用 formControl 的 updateValueandValidity 才能使 formControl 正确更新值和有效性。
  • 但是,如果我在调用updateValueAndValidity() 之前调用setErrors() 方法,它会从子formControl 中删除我在setErrors() 中指定的错误。
猜你喜欢
  • 2018-01-15
  • 1970-01-01
  • 2022-11-26
  • 2021-05-06
  • 1970-01-01
  • 1970-01-01
  • 2017-04-06
  • 2021-10-10
  • 2018-06-01
相关资源
最近更新 更多