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: []
  }
});