gpt4 book ai didi

Angular 响应式(Reactive)表单自定义控件异步验证

转载 作者:行者123 更新时间:2023-12-03 14:38:34 24 4
gpt4 key购买 nike

更新:
异步验证问题已成功解决。但是初始验证状态还有另一个问题。
查看最新答案。
这是诀窍:

  • 具有实现 ControlValueAccessor 接口(interface)的组件用作自定义控件。
  • 该组件在某些响应式(Reactive)表单中用作 FormControl。
  • 此自定义控件具有异步验证器。

  • 问题:
    值更改后立即调用来自 ControlValueAccessor 接口(interface)的方法 validate() 并且不等待异步验证器。当然,控制是无效的和未决的(因为正在进行验证),主窗体也将是无效的和未决的。一切正常。
    但。当异步验证器完成验证并返回 null(表示值有效)时,自定义控件将有效并且状态也更改为有效,但父级仍然无效且处于挂起状态,因为来自值访问器的 validate() 尚未再次调用。
    我试图从 validate() 方法返回 observable,但主窗体将其解释为错误对象。
    我找到了解决方法:当异步验证器完成验证时,从自定义控件传播更改事件。它迫使主窗体再次调用 validate() 方法并获得正确的有效状态。但它看起来又脏又糙。
    问题是:
    必须做什么才能使父表单由子自定义控件的异步验证器管理?必须说它与同步验证器配合得很好。
    所有项目代码都可以在这里找到:
    https://stackblitz.com/edit/angular-fdcrbl
    主要表格模板:
    <form [formGroup]="mainForm">
    <child-control formControlName="childControl"></child-control>
    </form>
    主窗体类:
    import { Component, OnInit } from "@angular/core";
    import { FormBuilder, FormGroup } from "@angular/forms";

    @Component({
    selector: "my-app",
    templateUrl: "./app.component.html"
    })
    export class AppComponent implements OnInit {
    mainForm: FormGroup;

    constructor(private formBuilder: FormBuilder) {}

    ngOnInit() {
    this.mainForm = this.formBuilder.group({
    childControl: this.formBuilder.control("")
    });
    }
    }
    自定义子控件模板:
    <div [formGroup]="childForm">
    <div class="form-group">
    <label translate>Child control: </label>
    <input type="text" formControlName="childControl">
    </div>
    </div>
    自定义子控件类:
    import { Component, OnInit } from "@angular/core";
    import { AppValidator } from "../app.validator";
    import {
    FormGroup,
    AsyncValidator,
    FormBuilder,
    NG_VALUE_ACCESSOR,
    NG_ASYNC_VALIDATORS,
    ValidationErrors,
    ControlValueAccessor
    } from "@angular/forms";
    import { Observable } from "rxjs";
    import { map, first } from "rxjs/operators";

    @Component({
    templateUrl: "./child-control.component.html",
    selector: "child-control",
    providers: [
    {
    provide: NG_VALUE_ACCESSOR,
    useExisting: ChildControlComponent,
    multi: true
    },
    {
    provide: NG_ASYNC_VALIDATORS,
    useExisting: ChildControlComponent,
    multi: true
    }
    ]
    })
    export class ChildControlComponent
    implements ControlValueAccessor, AsyncValidator, OnInit {
    childForm: FormGroup;

    constructor(
    private formBuilder: FormBuilder,
    private appValidator: AppValidator
    ) {}

    ngOnInit() {
    this.childForm = this.formBuilder.group({
    childControl: this.formBuilder.control(
    "",
    [],
    [this.appValidator.asyncValidation()]
    )
    });
    this.childForm.statusChanges.subscribe(status => {
    console.log("subscribe", status);
    });
    }

    // region CVA
    public onTouched: () => void = () => {};

    writeValue(val: any): void {
    if (!val) {
    return;
    }
    this.childForm.patchValue(val);
    }

    registerOnChange(fn: () => void): void {
    this.childForm.valueChanges.subscribe(fn);
    }

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

    setDisabledState?(isDisabled: boolean): void {
    isDisabled ? this.childForm.disable() : this.childForm.enable();
    }

    validate(): Observable<ValidationErrors | null> {
    console.log('validate');
    // return this.taxCountriesForm.valid ? null : { invalid: true };
    return this.childForm.statusChanges.pipe(
    map(status => {
    console.log('pipe', status);
    return status == "VALID" ? null : { invalid: true };
    }),
    );
    }
    // endregion
    }

    最佳答案

    我尝试了不同的方法和技巧。但是正如 Andrei Gătej 提到的主窗体取消订阅子控件的更改。

    我的目标是保持自定义控件的独立性,并且不要将验证移至主窗体。它花了我一副白发,但我认为我找到了可以接受的解决方法。

    需要在子组件的验证功能内从主窗体传递控制并在那里管理有效性。
    在现实生活中,它可能看起来像:

      validate(control: FormControl): Observable<ValidationErrors | null> {
    return this.childForm.statusChanges.pipe(
    map(status => {
    if (status === "VALID") {
    control.setErrors(null);
    }
    if (status === "INVALID") {
    control.setErrors({ invalid: true });
    }
    // you still have to return correct value to mark as PENDING
    return status == "VALID" ? null : { invalid: true };
    }),
    );
    }

    关于Angular 响应式(Reactive)表单自定义控件异步验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59313428/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com