首页 文章

Angular 7:需要帮助理解在构建具有多级嵌套字段组的表单时遇到的问题

提问于
浏览
0

正如您在下面的附图中看到的,我在Angular 7中构建了一个表单 . 表单包含多个级别的嵌套字段组 . 按“添加轨道”按钮时,外部字段组被推送到dom . 然后在里面你可以按“”在每个外部字段组中添加字段 .

Problem 1: 我继续收到以下错误,"Add Track"只将完整的字段组推送到索引1,传递它缺少"+"按钮的字段,这些按钮由HTML中的嵌套* ngFor循环填充 .

Error:

ERROR Error: Cannot find control with path: 'albumTracks -> 1 -> audioSources -> 1'
    at _throwError (forms.js:1775)
    at setUpFormContainer (forms.js:1757)
    at FormGroupDirective.push../node_modules/@angular/forms/fesm5/forms.js.FormGroupDirective.addFormGroup (forms.js:4541)
    at FormGroupName.push../node_modules/@angular/forms/fesm5/forms.js.AbstractFormGroupDirective.ngOnInit (forms.js:1887)
    at checkAndUpdateDirectiveInline (core.js:9243)
    at checkAndUpdateNodeInline (core.js:10507)
    at checkAndUpdateNode (core.js:10469)
    at debugCheckAndUpdateNode (core.js:11102)
    at debugCheckDirectivesFn (core.js:11062)
    at Object.eval [as updateDirectives] (AddAlbumsDinamicComponent.html:103)

Problem 2: 当我填写表单并单击"Save"按钮然后执行onSubmit()方法并通过以下方式获取所有输入的表单值:"this.albumForm.value"时,我丢失了一些我输入到字段中的值,这些值是通过按"Add Track"和"+"按钮动态推送的 .

试图在网上找到答案,但找不到任何类似于我想做的事情 . 所有在线示例均适用于简单表单,而不适用于多级嵌套表单组 . 也是Angular的新手,需要帮助 . S.O.S,非常感谢你的帮助 .

enter image description here

component.ts

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, FormArray } from '@angular/forms';
import { PostRequestService } from '../post-request.service';

@Component({
  selector: 'app-add-albums-dinamic',
  templateUrl: './add-albums-dinamic.component.html',
  styleUrls: ['./add-albums-dinamic.component.css']
})

export class AddAlbumsDinamicComponent implements OnInit {

  albumForm: FormGroup;
  items: FormArray;
  arrayElement: FormArray;
  submitted = false;

  constructor(private formBuilder: FormBuilder, private postRequestService: PostRequestService) {}

  ngOnInit() {
    this.albumForm = this.formBuilder.group({
      albumTitle: '',
      albumCoverImage: '',
      datePublished: '',
      albumPurchaseSources: this.formBuilder.array([ this.createAlbumPurchaseSource() ]),
      albumTracks: this.formBuilder.array([ this.albumTracksDetails() ])
    });
  }

  createAlbumPurchaseSource(): FormGroup {
    return this.formBuilder.group({
      albumPurchaseSourceName: '',
      albumPurchaseURL: ''
    });
  }

  createAudioSource(): FormGroup {
    return this.formBuilder.group({
      audioSourceName: '',
      audioSourceURL: ''
    });
  }

  createVideoSource(): FormGroup {
    return this.formBuilder.group({
      videoSourceName: '',
      videoSourceURL: ''
    });
  }

  createTrackPurchaseSource(): FormGroup {
    return this.formBuilder.group({
      trackPurchaseSourceName: '',
      trackPurchaseSourceURL: ''
    });
  }

  albumTracksDetails(): FormGroup {
    return this.formBuilder.group({
      trackTitle: '',
      trackGenre: '',
      audioSources: this.formBuilder.array([ this.createAudioSource() ]),
      videoSources: this.formBuilder.array([ this.createVideoSource() ]),
      trackPurchaseSources: this.formBuilder.array([ this.createTrackPurchaseSource() ]),
      downloadURL: ''
    });
  }


  addAudioSource(i: number): void {
    const control = (<FormArray>this.albumForm.controls['albumTracks']).at(i).get('audioSources') as FormArray;
    control.push(this.createAudioSource());
  }

  addVideoSource(i: number): void {
    const control = (<FormArray>this.albumForm.controls['albumTracks']).at(i).get('videoSources') as FormArray;
    control.push(this.createVideoSource());
  }

  addTrackPurchaseSource(i: number): void {
    const control = (<FormArray>this.albumForm.controls['albumTracks']).at(i).get('trackPurchaseSources') as FormArray;
    control.push(this.createTrackPurchaseSource());
  }

  addTracks(): void {
    this.items = this.albumForm.get('albumTracks') as FormArray;
    this.items.push(this.albumTracksDetails());
  }

  addAlbumPurchaseSources(): void {
    this.items = this.albumForm.get('albumPurchaseSources') as FormArray;
    this.items.push(this.createAlbumPurchaseSource());
  }


  onSubmit() {
      this.submitted = true;

      this.postRequestService.
      postRequest(this.albumForm.value)
      .subscribe(
          (val) => {
              console.log("POST call successful value returned in body",
                          val);
          },
          response => {
              console.log("POST call in error", response);
          },
          () => {
              console.log("The POST observable is now completed.");
          });
  }


}

component.html

<div class="container">
  <div id="outer-container">
    <div id="sidebar">
      <div class="mycontent-left">
        <app-artist-admin-sidebar></app-artist-admin-sidebar>
      </div>
    </div>
    <div id="content">
      <form [formGroup]="albumForm" (ngSubmit)="onSubmit()" novalidate>
        <div><font size="4">Album Details:</font></div>
        
<div class="row"> <div class="col"> <div class="col-sm-2 control-label"><font size="3">Album Title:</font></div> <div class="col-sm-3 nopadding"> <input type="text" class="form-control" id="album_title" name="album_title" formControlName="albumTitle" placeholder="Album Title"> </div> </div> </div>
<div class="row"> <div class="col"> <div class="col-sm-3 control-label"><font size="3">Album Cover Image:</font></div> <div class="col-sm-3 nopadding"> <input type="file" class="form-control" id="cover_image" name="cover_image" formControlName="albumCoverImage" placeholder="Album Cover Image"> </div> </div> </div>
<div class="row"> <div class="col"> <div class="col-sm-3 control-label"><font size="3">Date Published:</font></div> <div class="col-sm-3 nopadding"> <input type="date" class="form-control" id="date_published" name="date_published" formControlName="datePublished" placeholder="Date Published"> </div> </div> </div>
<div formArrayName="albumPurchaseSources" *ngFor="let item of albumForm.get('albumPurchaseSources').controls; let i = index;"> <div [formGroupName]="i"> <div class="row"> <div class="col"> <div class="col-sm-2 control-label"><font size="3">Album Purchase Source:</font></div> <div class="col-sm-3 nopadding"> <input type="text" class="form-control" id="album_purchase_source_name" name="album_purchase_source_name" formControlName="albumPurchaseSourceName" placeholder="Source Name"> </div> <div class="col-sm-3 nopadding"> <div class="form-group"> <div class="input-group"> <input type="text" class="form-control" id="album_purchase_url" name="album_purchase_url" formControlName="albumPurchaseURL" placeholder="URL"> <div class="input-group-btn"> <button class="btn btn-success" type="button" (click)="addAlbumPurchaseSources();"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></button> </div> </div> </div> </div> </div> </div> </div> </div> <hr/>
<div><font size="4">Album Tracks Details:</font></div>
<div formArrayName="albumTracks" *ngFor="let item of albumForm.get('albumTracks').controls; let i = index;"> <div [formGroupName]="i"> <div class="row"> <div class="col"> <div class="col-sm-2 control-label"><font size="3">Track Title:</font></div> <div class="col-sm-3 nopadding"> <input type="text" class="form-control" id="track_title" name="track_title" formControlName="trackTitle" placeholder="Track Title"> </div> </div> </div>
<div class="row"> <div class="col"> <div class="col-sm-2 control-label"><font size="3">Track Genre:</font></div> <div class="col-sm-3 nopadding"> <input type="text" class="form-control" id="genre" name="genre" formControlName="trackGenre" placeholder="Genre"> </div> </div> </div>
<div formArrayName="audioSources" *ngFor="let audioItem of item.controls['audioSources'].controls; let audioi=index;"> <div [formGroupName]="i"> <div class="row"> <div class="col"> <div class="col-sm-2 control-label"><font size="3">Audio:</font></div> <div class="col-sm-3 nopadding"> <input type="text" class="form-control" id="audio_source_name" name="audio_source_name" formControlName="audioSourceName" placeholder="Audio Source Name"> </div> <div class="col-sm-3 nopadding"> <div class="form-group"> <div class="input-group"> <input type="text" class="form-control" id="audio_url" name="audio_url" formControlName="audioSourceURL" placeholder="Audio Source URL"> <div class="input-group-btn"> <button class="btn btn-success" type="button" (click)="addAudioSource(i);"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></button> </div> </div> </div> </div> </div> </div> </div> </div>
<div formArrayName="videoSources" *ngFor="let videoItem of item.controls['videoSources'].controls; let videoi = index;"> <div [formGroupName]="i"> <div class="row"> <div class="col"> <div class="col-sm-2 control-label"><font size="3">Video:</font></div> <div class="col-sm-3 nopadding"> <input type="text" class="form-control" id="video_source_name" name="video_source_name" formControlName="videoSourceName" placeholder="Video Source Name"> </div> <div class="col-sm-3 nopadding"> <div class="form-group"> <div class="input-group"> <input type="text" class="form-control" id="video_url" name="video_url" formControlName="videoSourceURL" placeholder="Video Source URL"> <div class="input-group-btn"> <button class="btn btn-success" type="button" (click)="addVideoSource(i);"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></button> </div> </div> </div> </div> </div> </div> </div> </div>
<div formArrayName="trackPurchaseSources" *ngFor="let trackPurchaseItem of item.controls['trackPurchaseSources'].controls; let purchasei = index;"> <div [formGroupName]="i"> <div class="row"> <div class="col"> <div class="col-sm-2 control-label"><font size="3">Track Purchase Source:</font></div> <div class="col-sm-3 nopadding"> <input type="text" class="form-control" id="purchase_source_name" name="purchase_source_name" formControlName="trackPurchaseSourceName" placeholder="Purchase Source Name"> </div> <div class="col-sm-3 nopadding"> <div class="form-group"> <div class="input-group"> <input type="text" class="form-control" id="purchase_url" name="purchase_url" formControlName="trackPurchaseSourceURL" placeholder="Purchase Source URL"> <div class="input-group-btn"> <button class="btn btn-success" type="button" (click)="addTrackPurchaseSource(i);"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></button> </div> </div> </div> </div> </div> </div> </div> </div>
<div class="row"> <div class="col"> <div class="col-sm-2 control-label"><font size="3">Download:</font></div> <div class="col-sm-3 nopadding"> <input type="text" class="form-control" id="download_url" name="download_url" formControlName="downloadURL" placeholder="Download URL"> </div> </div> </div>
<hr>
</div> </div> <div class="form-group"> <button class="btn btn-success" type="button" (click)="addTracks();">Add Track</button> </div> <div class="form-group"> <button class="btn btn-primary">Save</button> </div> </form> </div> </div> </div>

1 回答

  • 2

    在这里工作:https://stackblitz.com/edit/so-53246132

    Problem #1:

    <div formArrayName="audioSources" *ngFor="let audioItem of item.controls['audioSources'].controls; let audioi=index;">
              <div [formGroupName]="i">
    

    但应该是:

    <div formArrayName="audioSources" *ngFor="let audioItem of item.controls['audioSources'].controls; let audioi=index;">
              <div [formGroupName]="audioi">
    

    videoipurchasei 也是如此 .

    Problem #2:

    addTracks(): void {
        (this.albumForm.get('albumTracks') as FormArray).push(this.albumTracksDetails());
        // why? what is items?
        // this.items = this.albumForm.get('albumTracks') as FormArray;
        // this.items.push(this.albumTracksDetails());
      }
    

    也可能会有变化:

    addAlbumPurchaseSources(): void {
        this.items = this.albumForm.get('albumPurchaseSources') as FormArray;
        this.items.push(this.createAlbumPurchaseSource());
      }
    

相关问题