我的应用程序中有一个复杂的表单.其中一部分要求提供地址,他们必须输入物理地址.有一个复选框用于标记邮寄地址是否相同.如果是,则邮寄地址字段不是必填项(这是默认设置).如果取消选中该复选框,则需要输入邮寄地址.这种方法是有效的,因为最初不需要邮寄地址,但在取消选中该框后,邮寄地址就变成必需的.但如果他们再次判断,他们仍然被要求输入邮寄地址.下面是相关的代码片段:

// form declaration
const personalInfoForm = this._fb.group(
  {
    sameAddress: [true],
    physicalAddress: this._fb.group({
      line1: [
        "",
        [Validators.required, MhaValidators.validPhysicalStreetAddress],
      ],
      city: ["", [Validators.required]],
      state: ["", [Validators.required]],
      zip: ["", [Validators.required, MhaValidators.validZipCode]],
    }),
    mailingAddress: this._fb.group({
      line1: [""],
      city: [""],
      state: [""],
      zip: [""],
    }),
  }
);

// valueChanges for same address
this.personalInfoForm
  .get("sameAddress")
  .valueChanges.pipe(
    startWith(this.personalInfoForm.get("sameAddress").value),
    tap((sameAddress: boolean) => {
      if (sameAddress) {
        this.personalInfoForm.controls.mailingAddress = this._fb.group({
          line1: [""],
          city: [""],
          state: [""],
          zip: [""],
        });
      } else {
        this.personalInfoForm.controls.mailingAddress = this._fb.group({
          line1: ["", [Validators.required]],
          city: ["", [Validators.required]],
          state: ["", [Validators.required]],
          zip: ["", [Validators.required, MhaValidators.validZipCode]],
        });
      }

      this.personalInfoForm.controls.mailingAddress.updateValueAndValidity();
      this.personalInfoForm.updateValueAndValidity();
    }),
    untilDestroyed(this)
  )
  .subscribe();

// I also tried this for updating the validators:
this.personalInfoForm
  .get("sameAddress")
  .valueChanges.pipe(
    startWith(this.personalInfoForm.get("sameAddress").value),
    tap((sameAddress: boolean) => {
      const mailingAddress: FormGroup = this.personalInfoForm.get(
        "mailingAddress"
      ) as FormGroup;
      if (sameAddress) {
        // remove validators from mailing address
        mailingAddress.get("line1").clearValidators();
        mailingAddress.get("city").clearValidators();
        mailingAddress.get("state").clearValidators();
        mailingAddress.get("zip").clearValidators();
      } else {
        // add validators to mailing address
        mailingAddress.get("line1").addValidators([Validators.required]);
        mailingAddress.get("city").addValidators([Validators.required]);
        mailingAddress.get("state").addValidators([Validators.required]);
        mailingAddress
          .get("zip")
          .addValidators([Validators.required, MhaValidators.validZipCode]);
      }

      this.personalInfoForm.updateValueAndValidity();
    }),
    untilDestroyed(this)
  )
  .subscribe();

本质上,我想在sameAddress控件在true和false之间来回切换时添加或删除字段的验证器.

目前,如果它们不更改相同的地址控件,则该表单在技术上是有效的.如果他们取消选中,则需要填写邮寄地址,即使他们重新选中该复选框也是如此.

我不确定为什么有效性没有正确更新.知道为什么吗?

推荐答案

下面是一个基本的工作示例,我认为一旦设置了验证器,就需要运行该特定表单控件的updateValueAndValidity,然后代码运行得很好!

import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import {
  FormBuilder,
  FormGroup,
  ReactiveFormsModule,
  Validators,
} from '@angular/forms';
import { bootstrapApplication } from '@angular/platform-browser';
import { tap } from 'rxjs';
import { startWith } from 'rxjs/operators';
import 'zone.js';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, ReactiveFormsModule],
  template: `
    <form [formGroup]="personalInfoForm" (ngSubmit)="onSubmit()">
      <input formControlName="sameAddress" type="checkbox"/>
    <fieldset formGroupName="physicalAddress">
    physicalAddress | line1 : 
      <input formControlName="line1" type="text"/>

      </fieldset>
    <fieldset formGroupName="mailingAddress">
    mailingAddress | line1 : 
      <input formControlName="line1" type="text"/>

      </fieldset>
      <button type="submit">submit</button>
    </form>
  `,
})
export class App {
  name = 'Angular';
  personalInfoForm: FormGroup = new FormGroup({});

  constructor(private _fb: FormBuilder) {}

  onSubmit() {
    if (this.personalInfoForm.invalid) {
      alert('invalid');
    }
    console.log('submit');
  }

  ngOnInit(): void {
    const personalInfoForm = this._fb.group({
      sameAddress: [true],
      physicalAddress: this._fb.group({
        line1: ['', [Validators.required]],
      }),
      mailingAddress: this._fb.group({
        line1: [''],
      }),
    });
    this.personalInfoForm = personalInfoForm;

    // I also tried this for updating the validators:
    this.personalInfoForm!.get('sameAddress')!
      .valueChanges.pipe(
        startWith(this.personalInfoForm.get('sameAddress')!.value),
        tap((sameAddress: boolean) => {
          console.log(sameAddress);
          const mailingAddress: FormGroup = this.personalInfoForm.get(
            'mailingAddress'
          ) as FormGroup;
          const mailAddressLine1Ctrl = mailingAddress.get('line1');
          if (sameAddress) {
            // remove validators from mailing address
            mailAddressLine1Ctrl!.clearValidators();
          } else {
            // add validators to mailing address
            mailAddressLine1Ctrl!.addValidators([Validators.required]);
          }

          mailAddressLine1Ctrl!.updateValueAndValidity(); // <-- fix here
        })
      )
      .subscribe();
  }
}

bootstrapApplication(App);

stackblitz

Angular相关问答推荐

如何在Angular模块中的forRoot中注入配置

接收错误NullInjectorError:R3InjectorError(_AppModule)[config—config]....>过度安装Angular—Markdown—Editor

在状态更新后是否会再次触发ngrx效果?

如何在init为FALSE时以Angular 初始化主拇指擦除器-Swiper 11.0.6Angular 17 SSR

笔刷Angular 为17

如何确保[共享]组件是真正的哑组件?(Angular )

Angular 17+独立配置中main.ts bootstrap 调用的最佳实践

所有返回缺少权限或权限不足的FireBase项目.

根据环境变量动态加载Angular templateUrl

如何将模块导入独立指令

如何在 cypress 测试中实现拖放?

Angular 2 二传手与 ngOnChanges

运行 npm 测试(Angular 2 单元测试)后无法读取未定义的属性 subscribe

Angular 6在输入键上添加输入

如何将组件导入Angular 2中的另一个根组件

Angular将 Select 值转换为 int

Angular 4 错误:没有 HttpClient 的provider提供者

Angular 4 material表突出显示一行

Angular 应用程序必须在新部署后清除缓存

Angular 9 引入了需要加载的全局$localize()函数