【问题标题】:Angular 2 Accessing Nested FormArrays using FormBuilderAngular 2 使用 FormBuilder 访问嵌套的 FormArrays
【发布时间】:2017-02-22 21:04:22
【问题描述】:

首先,我只是从 Angular 2 开始,我正在尝试构建一个嵌套表单并对其进行验证。

这是我的 ts 文件的一部分:

ngOnInit() {
  this.myForm = this.formBuilder.group({
    projects: this.formBuilder.array([
      this.initProjects()
    ])
  });
}

initProjects(): any {
  return this.formBuilder.group({
    name: ['', [Validators.required, Validators.minLength(3)]],
    some_array: this.formBuilder.array([
      this.formBuilder.group({
        name: ['', Validators.required],
        attr: ['', Validators.required],
        some_id: [1, Validators.required]
      })
    ])
  });
}

addProject(): void {
  const control = < FormArray > this.myForm.controls['projects'];
  control.push(this.initProjects());
}

查看:

<form [formGroup]="myForm" novalidate (ngSubmit)="onSubmit(myForm)">
  <div formArrayName="projects">
    <div *ngFor="let project of myForm.controls.projects.controls; let i = index">
      <div [formGroupName]="i">
        <md-input placeholder="Name" formControlName="name"></md-input>
      </div>
      <div *ngFor="let some_obj of project.controls.some_array.controls; let x = index">
        <div [formGroupName]="x">
          <div>
            <md-input placeholder="Nome" formControlName="controls.some_array.controls.name"></md-input>
            <small *ngIf="!some_obj.controls.name.valid">
                    Nome é requerido
                  </small>
          </div>
          <md-input type="number" placeholder="Cost" formControlName="controls.some_array.controls.attr" required></md-input>
        </div>
      </div>
    </div>
  </div>
  <button type="submit" md-raised-button color="primary" [disabled]="!myForm.valid">Submit</button>
</form>
<pre>form value: <br>{{myForm.value | json}}</pre>

表单值的输出:

form value: 
{
  "projects": [
    {
      "name": "",
      "some_array": [
        {
          "name": "",
          "attr": "",
          "some_id": 1
        }
      ]
    },
    {
      "name": "",
      "some_array": [
        {
          "name": "",
          "attr": "",
          "some_id": 1
        }
      ]
    }
  ]
}

嗯,正如你所见,我有一些称为项目的数组,每个数组中有 1 个数组。

所以问题是我无法验证 some_array 数组的每个控件。

实际上我收到以下错误:

原始异常:找不到带有路径的控件:'projects -> 0 -> controls.some_array.controls.name PS:我已经试过把它放在一个div中,如下:

但我也遇到了错误:

找不到带有路径的控件:'projects -> some_array' 提前致谢。任何帮助将不胜感激。

【问题讨论】:

    标签: angular typescript angular2-forms


    【解决方案1】:

    试试下面的 HTML:

    <form [formGroup]="myForm" novalidate (ngSubmit)="onSubmit(myForm)">
        <div formArrayName="projects">
            <div [formGroupName]="i" *ngFor="let project of myForm.controls.projects.controls; let i = index">
                <md-input placeholder="Name" formControlName="name"></md-input>
                <div formArrayName="some_array">
                    <div [formGroupName]="x" *ngFor="let some_obj of project.controls.some_array.controls; let x = index">
                        <div>
                            <md-input placeholder="Nome" formControlName="name"></md-input>
                            <small *ngIf="!some_obj.controls.name.valid">Nome é requerido</small>
                        </div>
                        <md-input type="number" placeholder="Cost" formControlName="attr" required></md-input>
                    </div>
                </div>
            </div>
        </div>
        <button type="submit" md-raised-button color="primary" [disabled]="!myForm.valid">Submit</button>
    </form>
    <pre>form value: <br>{{myForm.value | json}}</pre>
    

    【讨论】:

    • 如果没有数组但是嵌套了fromGroup那么如何显示错误信息。
    【解决方案2】:

    在嵌套 formControlName 周围使用括号时,我遇到了同样的问题。例如(这是错误的):

    <div formArrayName="options">
                <ion-row *ngFor="let option of addProductForm.controls.options.controls; index as i;">
                  <ion-col no-padding [formGroupName]="i">
                    <ion-item>
                      <ion-label floating>Name</ion-label>
                      <ion-input type="text" [formControlName]="option_name"></ion-input>
                    </ion-item>
                  </ion-col>
                </ion-row>
              </div>
    

    formControlName="option_name" 必须不带括号

    【讨论】:

      【解决方案3】:

      使用嵌套数组。这是我在 angular6 中测试并完美运行的代码示例:

      app.component.ts:

      <pre>
      import { Component, OnInit } from '@angular/core';
      import { FormGroup, FormArray, FormBuilder, Validators, FormControl, NgControl  } from '@angular/forms';
      
      @Component({
        selector: 'app-root',
        templateUrl: './app.component.html'
      })
      export class AppComponent implements OnInit {
      
        proxyMedia: FormArray;
        formGroup: FormGroup;
      
        constructor(
          public formBuilder: FormBuilder
        ) {}
      
        ngOnInit() {
          this.formGroup = this.formBuilder.group({
            test_name: ['', [Validators.required]],
            tests: this.formBuilder.array([
              this.initTestsForm()
            ])
          });
        }
      
        initTestsForm(): any {
          return this.formBuilder.group({
            test_num: '',
            categorie: '',
            responses: this.formBuilder.array([
              this.initElement('responses')
            ])
          });
        }
      
        initElement(elementName: string): FormGroup {
          if(elementName === 'proxy_media') {
            return this.formBuilder.group(
              {
                prefixe: 'prefixe',
                confid: 'confid'
              }
            );
          } else if(elementName === 'tests') {
            return this.formBuilder.group({
              test_num: ['test_num', [Validators.required, Validators.minLength(2)]],
              categorie: ['categorie', [Validators.required, Validators.minLength(2)]],
              responses: this.formBuilder.array([
                this.initElement('responses')
              ])
            });
          } else if(elementName === 'responses') {
            return this.formBuilder.group({
              code_response: ['code_response', Validators.required],
              log_level: ['log_level', Validators.required]
            });
          }
        }
      
        addElement(formGroup: FormGroup, elementName: string): void {
          const control = < FormArray > formGroup.controls[elementName];
          control.push(this.initElement(elementName));
        }
      
        removeElement(formGroup: FormGroup, elementName: string, index: number): void {
          const control = <FormArray>formGroup.controls[elementName];
          control.removeAt(index);
        }
      
        onSubmit(o: any) {
          console.log(o);
        }
      
        debug(data: any) {
          console.warn('debug: data ');
          console.warn(data);
          console.warn('stop');
        }
      
      }
      </pre>
      
      <b>app.component.html:</b>
      
      <h1> Avaibility tests</h1>
      
      <form [formGroup]="formGroup" novalidate (ngSubmit)="onSubmit(formGroup)">
          <input placeholder="Test name" formControlName="test_name">
      
          <hr>
          <h3>Tests</h3>
          <div formArrayName="tests">
              <div [formGroupName]="testIndex" *ngFor="let test of formGroup.controls.tests.controls; let testIndex = index">
                <h2> Test number #{{testIndex}}</h2>
                <input placeholder="Test number" formControlName="test_num">
                <input placeholder="Category" formControlName="categorie">
      
                  <h3>Responses</h3>
                  <hr>
                  <div formArrayName="responses">
                      <div [formGroupName]="responseIndex" *ngFor="let response of test.controls.responses.controls; let responseIndex = index">
                          <div>
                            <h4> HTTP Response #{{testIndex}}.{{responseIndex}}</h4>
                            <input placeholder="Code response" formControlName="code_response">
                            <small *ngIf="!response.controls.code_response.valid">code response required</small>
                            <input placeholder="Log level" formControlName="log_level">
                          </div>
                          <button type="button" (click)='removeElement(test,"responses",responseIndex)'>Remove Response</button>
                      </div>
                  </div>
                  <hr>
                  <button type="button" (click)="addElement(test,'responses')">Add Response</button>
                  <br><br>
                  <button type="button" (click)='removeElement(formGroup,"tests",testIndex)'>Remove Test</button>
              </div>
          </div>
      
          <hr>
          <button type="button" (click)='addElement(formGroup,"tests")'>Add Test</button>
      
          <hr>
          <button type="submit" md-raised-button color="primary" [disabled]="!formGroup.valid">Submit</button>
      </form>
      
      <br><br>
      </pre>
      
      <b>Add this code at the bottom to debug:</b>
      <pre>form value: <br>{{formGroup.value | json}}</pre>
      

      【讨论】:

        猜你喜欢
        • 2018-01-12
        • 2017-08-19
        • 2017-08-14
        • 1970-01-01
        • 2017-12-21
        • 2018-10-11
        • 1970-01-01
        • 2011-06-18
        • 1970-01-01
        相关资源
        最近更新 更多