如何使用angulars controlvalue访问器触发表单验证



当使用角度形式时,通常的方法是将形式元素(如输入(直接放入形式中

<form>
<input>
</form>

当这个表单被提交并且输入有一个验证器时,例如必需的。表单输入经过验证,如果无效,我们可以向用户显示。。。太棒了

为了能够重用自定义输入,我们可以创建一个包含此输入+额外内容的组件。

<form>
<custom-component>
</form>

检查此堆栈litz:https://stackblitz.com/edit/components-issue-whxtth?file=src%2Fapp%2Fuser%2Fuser.component.html

当点击提交按钮时,只有一个输入被验证。如果您与两个输入交互,它们将验证

就我所见,CVA组件没有什么奇怪的地方。

@Component({
selector: "user",
templateUrl: "./user.component.html",
styleUrls: ["./user.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class UserComponent implements ControlValueAccessor {
constructor(@Optional() @Self() public ngControl: NgControl) {
if (this.ngControl != null) {
// Setting the value accessor directly (instead of using the providers) to avoid running into a circular import.
this.ngControl.valueAccessor = this;
}
}
onTouched = (_value?: any) => {};
onChanged = (_value?: any) => {};
writeValue(val: string): void {}
registerOnChange(fn: any): void {
this.onChanged = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
}

正如我所说,您的输入对验证没有反应的主要原因是您的组件配置为changeDetection: ChangeDetectionStrategy.OnPush,这将使您的组件只对受限操作做出反应:

  1. 输入引用更改
  2. 源自组件或其子级之一的事件
  3. 在视图中使用异步管道
  4. 显式运行更改检测 (将提供解决方法(

所以你有两个选项:

  1. 采用默认的更改检测策略(就像Angular Material一样(
  2. 选择一个丑陋的变通方法

解决方法如下:

constructor(
@Optional() @Self() public ngControl: NgControl,
private cdr: ChangeDetectorRef // import the CDR
) {
if (this.ngControl != null) {
this.ngControl.valueAccessor = this;
const { _parent } = this.ngControl as any; // this is not a public property
// and refers to the parent form
_parent.ngSubmit.subscribe((r: any) => { // this is fired when the form submitted
this.cdr.detectChanges(); // detect changes manually
});
}
}

Stacklitz

这将适用于您有一个窗体作为父窗体的情况。有了一些空检查,它将始终如一地工作。但是,您可能会遇到其他一些场景,在这些场景中,您可能没有机会触发手动更改检测,这将严重损害组件的可重用性。

最新更新