Angular:为什么我的formArray无法验证或更新?

时间:2019-11-21 06:13:29

标签: angular typescript formarray ng-zorro-antd

我正在尝试获取一组表单字段来验证或更新我的父表单组。 有人可以告诉我我在做什么错吗?

我基本上想要实现的是添加一个具有多个表单域的新“供应商行”。 并验证每个字段。当前,只有formGroup的外部字段正在验证。我也不想验证每个formArray字段。我正在使用Ant的ng-zorro框架,如果有帮助的话。 预先感谢。

代码如下:

new-project.component.html

<div nz-row nzGutter="16">
  <div nz-col>
    <h2>Create new Project</h2>
  </div>
</div>
<div nz-row nzGutter="16">
  <div nz-col nzSpan="6" nzOffset="18">
    <button nz-button nzType="primary" nzBlock>
      <i nz-icon nzType="download"></i>Primary
    </button>
  </div>
</div>
<form nz-form nzLayout="vertical" [formGroup]="validateForm" (ngSubmit)="submitForm()">
  <div nz-row nzGutter="16">
    <div nz-col nzSpan="6">
      <nz-form-item>
        <nz-form-label>Project Name</nz-form-label>
        <nz-form-control nzErrorTip="Please enter a project name">
          <input formControlName="projectName" nz-input placeholder="Project Name" />
        </nz-form-control>
      </nz-form-item>
    </div>
    <div nz-col nzSpan="6">
      <nz-form-item>
        <nz-form-label>Company Code</nz-form-label>
        <nz-form-control nzErrorTip="Please select a company code" nzHasFeedback>
          <app-company-select formControlName="selectedCompanyValue"></app-company-select>
        </nz-form-control>
      </nz-form-item>
    </div>
  </div>
  <div nz-row nzGutter="16">
    <div nz-col nzSpan="5">
      Vendor
    </div>
    <div nz-col nzSpan="4">
      Budget
    </div>
    <div nz-col nzSpan="3">
      Available Budget
    </div>
    <div nz-col nzSpan="4">
      Budget to use in Project
    </div>
    <div nz-col nzSpan="2">
      Currency
    </div>
    <div nz-col nzSpan="2">
      Layer 1
    </div>
    <div nz-col nzSpan="2">
      Layer 2
    </div>
    <div nz-col nzSpan="2">
      Layer 3
    </div>
  </div>
  <div formArrayName="projectHeaders">
    <ng-container *ngFor="let projectHeader of validateForm.get('projectHeaders').controls; let i = index" formGroupName="{{i}}">
      <div nz-row nzGutter="16">
        <div nz-col nzSpan="5">
          <nz-form-item>
            <nz-form-control nzErrorTip="Please select a vendor" nzHasFeedback>
              <app-vendor-search formControlName="selectedVendorValue"></app-vendor-search>
            </nz-form-control>
          </nz-form-item>
        </div>
        <div nz-col nzSpan="4">
          <nz-form-item>
            <nz-form-control nzErrorTip="Please select a budget" nzHasFeedback>
              <nz-select formControlName="selectedBudgetValue" nzAllowClear nzPlaceHolder="Budgets">
                <nz-option *ngFor="let o of listOfBudgets" [nzLabel]="o.text" [nzValue]="o.value"> </nz-option>
              </nz-select>
            </nz-form-control>
          </nz-form-item>
        </div>
        <div nz-col nzSpan="3">
          <nz-form-item>
            <nz-form-control>
              <input nz-input placeholder="" formControlName="availableBudget" [disabled]="true" />
            </nz-form-control>
          </nz-form-item>
        </div>
        <div nz-col nzSpan="4">
          <nz-form-item>
            <nz-form-control nzErrorTip="Make sure you have selected a valid budget amount.">
              <nz-input-number formControlName="budgetToUseInProject" [nzFormatter]="parseCurrencyEUR" style="width: 100%;">
              </nz-input-number>
            </nz-form-control>
          </nz-form-item>
        </div>
        <div nz-col nzSpan="2">
          <nz-form-item>
            <nz-form-control>
              <input nz-input placeholder="" formControlName="currency" [disabled]="true" />
            </nz-form-control>
          </nz-form-item>
        </div>
        <div nz-col nzSpan="2">
          <nz-form-item>
            <nz-form-control nzErrorTip="Please select a layer" nzHasFeedback>
              <nz-select formControlName="layer1" nzAllowClear nzPlaceHolder="Layer 1">
                <nz-option *ngFor="let o of layerOneOptions" [nzLabel]="o.text" [nzValue]="o.value"> </nz-option>
              </nz-select>
            </nz-form-control>
          </nz-form-item>
        </div>
        <div nz-col nzSpan="2">
          <nz-form-item>
            <nz-form-control nzErrorTip="Please select a layer" nzHasFeedback>
              <nz-select formControlName="layer2" nzAllowClear nzPlaceHolder="Layer 2">
                <nz-option *ngFor="let o of layerOneTwoOptions" [nzLabel]="o.text" [nzValue]="o.value"> </nz-option>
              </nz-select>
            </nz-form-control>
          </nz-form-item>
        </div>
        <div nz-col nzSpan="2">
          <nz-form-item>
            <nz-form-control nzErrorTip="Please select a layer" nzHasFeedback>
              <nz-select formControlName="layer3" nzAllowClear nzPlaceHolder="Layer 3">
                <nz-option *ngFor="let o of layerThreeOptions" [nzLabel]="o.text" [nzValue]="o.value"> </nz-option>
              </nz-select>
            </nz-form-control>
          </nz-form-item>
        </div>
      </div>
    </ng-container>
  </div>
  <!-- <div formArrayName="projectHeaders">
    <ng-container *ngFor="let projectHeader of validateForm.get('projectHeaders').controls; let i = index">
      <app-vendor-line [group]="projectHeader"></app-vendor-line>
    </ng-container>
  </div> -->
  <div nz-row nzGutter="16">
    <div nz-col nzSpan="24">
      <nz-form-item>
        <nz-form-control nzErrorTip="Please">
          <button nz-button nzSize="large" nzType="primary" nzBlock>Primary</button>
        </nz-form-control>
      </nz-form-item>
    </div>
  </div>
</form>

new-project.component.ts

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators, FormControl, FormArray } from '@angular/forms';
import { formatNumber } from '@angular/common';

@Component({
  selector: 'app-new-project',
  templateUrl: './new-project.component.html',
  styleUrls: ['./new-project.component.css']
})
export class NewProjectComponent implements OnInit {
  validateForm: FormGroup;

  constructor(private fb: FormBuilder) {

    this.validateForm = this.fb.group({
      selectedCompanyValue: [null, [Validators.required]],
      projectName: [null, [Validators.required]],
      projectHeaders: this.fb.array([]),
      projectLines: []
    });
  }

  ngOnInit() {


    this.addHeaderLine();
  }

  submitForm(): void {
    // tslint:disable-next-line: forin
    for (const i in this.validateForm.controls) {
      this.validateForm.controls[i].markAsDirty();
      this.validateForm.controls[i].updateValueAndValidity();
      if (i === 'projectHeaders') {
        const control = this.validateForm.get('projectHeaders') as FormArray;
        for (const j of control.controls) {
          j.markAsDirty();
          j.updateValueAndValidity();
        }
      }
    }
  }

  initProjectHeader() {
    return this.fb.group({
      selectedVendorValue: [null, Validators.compose([Validators.required])],
      selectedBudgetValue: [null, Validators.compose([Validators.required])],
      availableBudget: [{value: 0, disabled: true }, Validators.compose([Validators.required])],
      budgetToUseInProject: [0, Validators.compose([Validators.required])],
      currency: [{value: 'EUR', disabled: true}, Validators.compose([Validators.required])],
      layer1: [null, Validators.compose([Validators.required])],
      layer2: [null, Validators.compose([Validators.required])],
      layer3: [null, Validators.compose([Validators.required])]
    });
  }

  addHeaderLine() {
    const control = this.validateForm.controls.projectHeaders as FormArray;
    control.push(this.initProjectHeader());
  }

  parseCurrencyEUR(value: number): string {
    return formatNumber(value, 'de_DE');
  }


}

2 个答案:

答案 0 :(得分:1)

使用Validators.required时,它将使表单无效或有效,并且如果要求失败,则该字段也将变为无效。因此,如果满足条件,它将使表格有效,否则无效。您可以将自定义验证信使放置在屏幕上,也可以将其边框设置为红色,然后禁用提交按钮,以显示该字段为必填字段,并且不允许提交

在CSS中:input.form-control.ng-invalid { border: 2px solid red; } 您的ts文件很好。只是需要添加验证消息或在不满足要求的情况下使字段边框变为红色。

答案 1 :(得分:0)

我设法弄清了问题所在。显然,您甚至必须将嵌套表单标记为脏表单并对其进行更新,因此我修改了onSubmit函数来做到这一点。感谢所有尝试提供帮助的其他人:)

submitForm(): void {
  // tslint:disable-next-line: forin
  for (const i in this.validateForm.controls) {
    this.validateForm.controls[i].markAsDirty();
    this.validateForm.controls[i].updateValueAndValidity();
    if (i === 'projectHeaders') {
      const control = this.validateForm.get('projectHeaders') as FormArray;
      // tslint:disable-next-line: forin
      for (const j in control.controls) {
        const controlTwo = control.controls[j] as FormGroup;
        // tslint:disable-next-line: forin
        for (const k in controlTwo.controls) {
          controlTwo.controls[k].markAsDirty();
          controlTwo.controls[k].updateValueAndValidity();
        }
      }
    }
    if (i === 'projectLines') {
      const control = this.validateForm.get('projectLines') as FormArray;
      // tslint:disable-next-line: forin
      for (const j in control.controls) {
        const controlTwo = control.controls[j] as FormGroup;
        // tslint:disable-next-line: forin
        for (const k in controlTwo.controls) {
          controlTwo.controls[k].markAsDirty();
          controlTwo.controls[k].updateValueAndValidity();
        }
      }
    }
  }
}