0

I'm trying to display add a playlist in Mat-dialog that has songs in a list using (formArray) like this: enter image description here

but I keep getting :

ERROR TypeError: Cannot read property 'map' of undefined

and my dialogue look this way: enter image description here

here's my code:

my 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>

and my 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);

  }  
  }

and finally, the component where I open the dialog and where my playlist class exist:

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);
  }

}

I don't understand why he's having a problem with
this.data.songs.map(song => this.formBuilder.group())

if anyone is familiar or can see what I'm missing please help me

2
  • please, add console.log(this.data) for DialogComponent in ngOnInit, and show output Commented May 30, 2020 at 21:02
  • 1
    @DMITRYTISHKIN I get [object Object] Commented May 30, 2020 at 21:04

1 Answer 1

2

songs is not initialized in the data being injected into DialogComponent. You can initialize it to an empty array when constructing the dialog data:

const dialogRef = this.dialog.open(DialogComponent, {
  width: '900px',
  data: {
    name: this.name,
    songs: []
  }
});
Sign up to request clarification or add additional context in comments.

1 Comment

thank you , I initialized it and I get rid of the map error :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.