ERROR TypeError: Cannot read property 'map' of undefined while trying to use formArray
ERROR TypeError: Cannot read property 'map' of undefined while trying to use formArray
我正在尝试在 Mat-dialog 中显示添加一个播放列表,该播放列表使用 (formArray) 在列表中包含歌曲,如下所示:
但我不断收到:
ERROR TypeError: Cannot read property 'map' of undefined
我的对话是这样的:
这是我的代码:
我的Dialog.component.html
<h1 mat-dialog-title>Create New Playlist
</h1>
<form [formGroup]='form'>
<div>
<div mat-dialog-content>
<mat-form-field class="input-width" appearance="standard">
<mat-label>Playlist name</mat-label>
<input matInput placeholder="" required formControlName="name" [(ngModel)]="data.name">
</mat-form-field>
<mat-form-field class="input-width" appearance="standard">
<mat-label>Description</mat-label>
<input matInput placeholder="" required formControlName="description" [(ngModel)]="data.description" >
</mat-form-field>
<mat-dialog-actions class="action-buttons">
<button mat-raised-button color="warn" (click)="close()" >Cancel </button>
<button mat-raised-button color="primary" [disabled] = "form.invalid" (click)="onSubmit()" [mat-dialog-close]="data">Submit</button>
</mat-dialog-actions>
<div formArrayName="songs" *ngIf="this.form">
<div *ngFor = "let song of songsform().controls; let i = index">
<div class="song-input-wrapper" [formGroupName]="i">
<mat-form-field appearance="standard">
<mat-label>Song Title</mat-label>
<input matInput placeholder="" required formControlName="title">
</mat-form-field>
<mat-form-field appearance="standard">
<mat-label>Artist</mat-label>
<input matInput placeholder="" required formControlName="artist">
</mat-form-field>
<mat-form-field appearance="standard">
<mat-label>Duration</mat-label>
<input matInput type="number" required formControlName="duration">
<span matSuffix>minutes</span>
</mat-form-field>
<button mat-icon-button color="primary" (click)="addSong()">
<mat-icon>add_circle</mat-icon>
</button>
<button
*ngIf="songsform().controls.length > 1"
mat-icon-button
color="warn"
(click)="removeSong(i)"
>
<mat-icon>remove_circle</mat-icon>
</button>
</div>
</div>
</div>
</div>
</div>
</form>
和我的 dialog.componenet.ts:
export class DialogComponent implements OnInit {
description:string;
songs: FormArray;
constructor(public service: PlaylistService,public dialogRef: MatDialogRef<DialogComponent>, private formBuilder: FormBuilder, @Inject(MAT_DIALOG_DATA) public data: Playlist )
{
}
form : FormGroup
songsform() :FormArray {
return this.form.get('songs') as FormArray ;
}
ngOnInit(): void {
if (!this.data) {
this.form = this.formBuilder.group({
name: [null, Validators.required],
description: [null, Validators.required],
songs: this.formBuilder.array([ this.createSong() ]),
});
} else {
this.form = this.formBuilder.group({
name: [this.data.name, Validators.required],
description: [this.data.description, Validators.required],
songs: this.formBuilder.array(
this.data.songs.map(song => this.formBuilder.group({
title: [song.title, Validators.required],
artist: [song.artist, Validators.required],
duration: [song.duration, Validators.compose([Validators.required, Validators.min(0)])],
}))
),
})}
}
close() {
this.dialogRef.close();
}
createSong(): FormGroup {
return this.formBuilder.group({
title: [null, Validators.required],
artist: [null, Validators.required],
duration: [null, Validators.compose([Validators.required, Validators.min(0)])],
});
}
addSong(): void {
this.songs.push(this.createSong());
}
removeSong(index: number): void {
if (this.songs.controls.length > 1) {
this.songs.removeAt(index);
}
}
onSubmit(){
this.dialogRef.close(this.form.value);
}
}
最后,我打开对话框的组件以及我的播放列表 class 所在的组件:
export interface Playlist {
name: string;
totalDuration: number;
totalSongs: number;
description: string;
songs: Song[];
}
export interface Song {
title: string;
artist: string;
duration: number;
}
@Component({
selector: 'app-playlist',
templateUrl: './playlist.component.html',
styleUrls: ['./playlist.component.css']
})
export class PlaylistComponent implements OnInit {
constructor(public dialog: MatDialog,public service: PlaylistService) { }
ngOnInit(): void {
}
playlists: Playlist[] = [
{
name: 'Kopikustik',
totalDuration: 5,
totalSongs: 2,
description: 'More than a coffee, this is all of your favorite accoustic songs.',
songs: [
{
title: 'Cigarettes of ours',
artist: 'Ardhito Pramono',
duration: 3
},
{
title: 'Walking Back Home',
artist: 'Vira Talisa',
duration: 2
},
]
},
{
name: 'Anime Hits',
totalDuration: 13,
totalSongs: 3,
description: 'Listen to your favorite Anime songs, all in one playlist.',
songs: [
{
title: 'Renai Circulation',
artist: 'Kana Hanazawa',
duration: 4
},
{
title: 'Platinum Disco',
artist: 'Tsukihi Phoenix',
duration: 4
},
{
title: 'Silhouette',
artist: 'KANA-BOON',
duration: 5
},
]
}
];
name:String
@Input() data: Playlist
openDialog(): void {
const dialogConfig = new MatDialogConfig();
dialogConfig.autoFocus = false;
const dialogRef = this.dialog.open(DialogComponent, {
width: '900px',
data: {
name : this.name,
/* description:'',
title:'',
artist:'',
duration:0*/
}
});
dialogRef.afterClosed().subscribe(result => {
console.log('The dialog was closed');
if (result) {
this.name = result.name;
alert("name is :"+ this.name)
}
});
}
deletePlaylist(i)
{
this.playlists.splice(i, 1);
}
}
我不明白他为什么对
有意见
this.data.songs.map(歌曲=> this.formBuilder.group())
如果有人熟悉或可以看到我遗漏的内容,请帮助我
songs
未在注入 DialogComponent
的数据中初始化。可以在构造对话数据时将其初始化为空数组:
const dialogRef = this.dialog.open(DialogComponent, {
width: '900px',
data: {
name: this.name,
songs: []
}
});
我正在尝试在 Mat-dialog 中显示添加一个播放列表,该播放列表使用 (formArray) 在列表中包含歌曲,如下所示:
但我不断收到:
ERROR TypeError: Cannot read property 'map' of undefined
我的对话是这样的:
这是我的代码:
我的Dialog.component.html
<h1 mat-dialog-title>Create New Playlist
</h1>
<form [formGroup]='form'>
<div>
<div mat-dialog-content>
<mat-form-field class="input-width" appearance="standard">
<mat-label>Playlist name</mat-label>
<input matInput placeholder="" required formControlName="name" [(ngModel)]="data.name">
</mat-form-field>
<mat-form-field class="input-width" appearance="standard">
<mat-label>Description</mat-label>
<input matInput placeholder="" required formControlName="description" [(ngModel)]="data.description" >
</mat-form-field>
<mat-dialog-actions class="action-buttons">
<button mat-raised-button color="warn" (click)="close()" >Cancel </button>
<button mat-raised-button color="primary" [disabled] = "form.invalid" (click)="onSubmit()" [mat-dialog-close]="data">Submit</button>
</mat-dialog-actions>
<div formArrayName="songs" *ngIf="this.form">
<div *ngFor = "let song of songsform().controls; let i = index">
<div class="song-input-wrapper" [formGroupName]="i">
<mat-form-field appearance="standard">
<mat-label>Song Title</mat-label>
<input matInput placeholder="" required formControlName="title">
</mat-form-field>
<mat-form-field appearance="standard">
<mat-label>Artist</mat-label>
<input matInput placeholder="" required formControlName="artist">
</mat-form-field>
<mat-form-field appearance="standard">
<mat-label>Duration</mat-label>
<input matInput type="number" required formControlName="duration">
<span matSuffix>minutes</span>
</mat-form-field>
<button mat-icon-button color="primary" (click)="addSong()">
<mat-icon>add_circle</mat-icon>
</button>
<button
*ngIf="songsform().controls.length > 1"
mat-icon-button
color="warn"
(click)="removeSong(i)"
>
<mat-icon>remove_circle</mat-icon>
</button>
</div>
</div>
</div>
</div>
</div>
</form>
和我的 dialog.componenet.ts:
export class DialogComponent implements OnInit {
description:string;
songs: FormArray;
constructor(public service: PlaylistService,public dialogRef: MatDialogRef<DialogComponent>, private formBuilder: FormBuilder, @Inject(MAT_DIALOG_DATA) public data: Playlist )
{
}
form : FormGroup
songsform() :FormArray {
return this.form.get('songs') as FormArray ;
}
ngOnInit(): void {
if (!this.data) {
this.form = this.formBuilder.group({
name: [null, Validators.required],
description: [null, Validators.required],
songs: this.formBuilder.array([ this.createSong() ]),
});
} else {
this.form = this.formBuilder.group({
name: [this.data.name, Validators.required],
description: [this.data.description, Validators.required],
songs: this.formBuilder.array(
this.data.songs.map(song => this.formBuilder.group({
title: [song.title, Validators.required],
artist: [song.artist, Validators.required],
duration: [song.duration, Validators.compose([Validators.required, Validators.min(0)])],
}))
),
})}
}
close() {
this.dialogRef.close();
}
createSong(): FormGroup {
return this.formBuilder.group({
title: [null, Validators.required],
artist: [null, Validators.required],
duration: [null, Validators.compose([Validators.required, Validators.min(0)])],
});
}
addSong(): void {
this.songs.push(this.createSong());
}
removeSong(index: number): void {
if (this.songs.controls.length > 1) {
this.songs.removeAt(index);
}
}
onSubmit(){
this.dialogRef.close(this.form.value);
}
}
最后,我打开对话框的组件以及我的播放列表 class 所在的组件:
export interface Playlist {
name: string;
totalDuration: number;
totalSongs: number;
description: string;
songs: Song[];
}
export interface Song {
title: string;
artist: string;
duration: number;
}
@Component({
selector: 'app-playlist',
templateUrl: './playlist.component.html',
styleUrls: ['./playlist.component.css']
})
export class PlaylistComponent implements OnInit {
constructor(public dialog: MatDialog,public service: PlaylistService) { }
ngOnInit(): void {
}
playlists: Playlist[] = [
{
name: 'Kopikustik',
totalDuration: 5,
totalSongs: 2,
description: 'More than a coffee, this is all of your favorite accoustic songs.',
songs: [
{
title: 'Cigarettes of ours',
artist: 'Ardhito Pramono',
duration: 3
},
{
title: 'Walking Back Home',
artist: 'Vira Talisa',
duration: 2
},
]
},
{
name: 'Anime Hits',
totalDuration: 13,
totalSongs: 3,
description: 'Listen to your favorite Anime songs, all in one playlist.',
songs: [
{
title: 'Renai Circulation',
artist: 'Kana Hanazawa',
duration: 4
},
{
title: 'Platinum Disco',
artist: 'Tsukihi Phoenix',
duration: 4
},
{
title: 'Silhouette',
artist: 'KANA-BOON',
duration: 5
},
]
}
];
name:String
@Input() data: Playlist
openDialog(): void {
const dialogConfig = new MatDialogConfig();
dialogConfig.autoFocus = false;
const dialogRef = this.dialog.open(DialogComponent, {
width: '900px',
data: {
name : this.name,
/* description:'',
title:'',
artist:'',
duration:0*/
}
});
dialogRef.afterClosed().subscribe(result => {
console.log('The dialog was closed');
if (result) {
this.name = result.name;
alert("name is :"+ this.name)
}
});
}
deletePlaylist(i)
{
this.playlists.splice(i, 1);
}
}
我不明白他为什么对
有意见
this.data.songs.map(歌曲=> this.formBuilder.group())
如果有人熟悉或可以看到我遗漏的内容,请帮助我
songs
未在注入 DialogComponent
的数据中初始化。可以在构造对话数据时将其初始化为空数组:
const dialogRef = this.dialog.open(DialogComponent, {
width: '900px',
data: {
name: this.name,
songs: []
}
});