<mat-error>在继承父组件自定义FormControl的验证时,在ControlValueAccessor中无法工作

3
在子级 ControlValueAccessor 组件中的 <mat-error> 对父级 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);
  }
}

我需要在这里添加一些额外的配置来让<mat-error>在父级formControl无效时显示吗?


如果您的子组件没有在providers中注册自己作为控件值访问器,那么它就不是一个控件值访问器。请搜索“ControlValueAccessor example”以查找示例,并查找组件装饰器中的providers声明。 - JB Nizet
2
我正在遵循这个方法:https://material.angular.io/guide/creating-a-custom-form-field-control#-code-ngcontrol-code-,否则我会得到“循环依赖错误”。 - Gourav Pokharkar
我认为更好的方法是使用自定义的errorStateMatcher。这个想法是,如果ngControl不正确,那么内部的mat-input也是不正确的,请参见https://stackoverflow.com/questions/58459617/component-for-wrap-angular-material-input-does-not-show-error-styles/58472470#58472470。注意:在stackblitz中,我添加了一个`@Input`错误来控制formGroup的错误。 - Eliseo
从您分享的链接中可以看到@GeniusGo。实际上,它只是说“如果需要直接访问控件-请从提供程序中删除ref转发”。 - simply good
2个回答

8
您需要手动在子组件中添加父控件验证器,像这样: 试一下这个:
 ngOnInit() {
    const validators = this.ngControl.control.validator;
    this.uniqueNameControl.setValidators(validators ? validators : null);
    this.uniqueNameControl.updateValueAndValidity();
 }

示例


好的。对于setErrors(),为什么我需要在this.uniqueNameControl.updateValueAndValidity();之后设置继承的错误呢?如果我不这样做,它就无法工作。从父级formControl继承验证器和错误的方式正确吗? - Gourav Pokharkar
1
当您动态添加验证器时,必须手动调用formControl的updateValueandValidity方法,以便正确更新formControl的值和有效性。 - Chellappan வ
但是,如果在调用updateValueAndValidity()之前调用setErrors()方法,则会从子formControl中删除我在setErrors()中指定的错误。 - Gourav Pokharkar
是的,我已经检查了。它按照我的期望工作。但问题在于,我必须在父组件中的某些事件上动态设置自定义错误,并使用@Input()将其指示给子组件,并且我必须使用setErrors()来设置这些错误。我们上面的讨论也与此问题有关。 - Gourav Pokharkar
errorState 是 FormField 组件的属性。我没有使用过它,详情请查看此处:https://material.angular.io/components/form-field/api#MatFormFieldControl - Chellappan வ
显示剩余6条评论

0
  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);
    });   }

请在您的答案中添加描述。 - mechnicov
提供能够解决问题的代码是很好的,但您也应该提供一个通俗易懂的描述来解释为什么它可以解决问题。简单的描述就足够了。 - Display name
2
虽然这段代码可能解决了问题,但是【包括解释】为何及如何解决问题将有助于提高您的帖子质量,很可能会得到更多的赞。请记住,您正在回答未来的读者提出的问题,而不仅仅是现在提问的人。请[编辑]您的答案以添加解释,并指出所适用的限制和假设。[来自审查] - double-beep

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接