如下图所示,我在 Angular 7 中构建了一个表单。表单包含多个级别的嵌套字段组。当按下“添加轨道”按钮时,外部字段组被推送到 dom。然后在里面你可以按“+”在每个外部字段组内添加字段。
问题 1: 我不断收到以下错误,并且“添加跟踪”仅将完整的字段组推入索引 1,传递它缺少带有“+”按钮的字段,这些按钮由 HTML 中的嵌套 *ngFor 循环填充。
错误:
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)
问题 2: 当我填写表单并单击“保存”按钮,然后执行 onSubmit() 方法并通过“this.albumForm.value”获取所有输入的表单值时,我缺少输入字段的一堆值,通过按“添加曲目”和“+”按钮动态推送。
试图在网上找到答案,但找不到与我正在尝试做的类似的事情。所有在线示例均适用于简单表单,而不适用于多级嵌套表单组。也是 Angular 的新手,需要帮助。SOS,非常感谢您的帮助。
组件.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.");
});
}
}
组件.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>
<br/>
<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>
<br/>
<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>
<br/>
<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>
<br/>
<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/>
<br/>
<div><font size="4">Album Tracks Details:</font></div>
<br/>
<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>
<br/>
<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>
<br/>
<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>
<br/>
<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>
<br/>
<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>
<br/>
<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>
<br/><hr><br/>
</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>