2

Hello I am building something similar to a music player app. I have a service set up grabbing the data from a JSON file that I have in a fixture. I can grab all top level data with *ngFor but once I start to ask for something like songs.parts.name this shows up undefined.

I have the *ngFor spitting out the top level key value pairs on a page and then I would like to be able to click on a specific song name and have it filter the data to find the correct song url.

How can I loop through that array and grab those objects?

Any help would be much appreciated.

JSON

{
  "songs": [
    {
      "name": "America The Beautiful",
      "difficulty": "Medium",
      "time": "3:38",
      "hasPianoWords": true,
      "hasPianoSolfa": false,
      "hasTrackWords": false,
      "parts": [
        {
          "name": "Baritone",
          "urls": {
            "pianoWords": "http://www.taabc.org/check-off-songs/baritone/america-the-beautiful/america-the-beautiful-piano-words.mp3",
            "pianoSolfa": "http://www.taabc.org/check-off-songs/baritone/america-the-beautiful/america-the-beautiful-piano-words.mp3",
            "trackWords": "http://www.taabc.org/check-off-songs/baritone/america-the-beautiful/america-the-beautiful-piano-words.mp3"
          }
        },
        {
          "name": "Bass",
          "urls": {
            "pianoWords": "http://www.taabc.org/check-off-songs/bass/america-the-beautiful/america-the-beautiful-piano-words.mp3",
            "pianoSolfa": "http://www.taabc.org/check-off-songs/bass/america-the-beautiful/america-the-beautiful-piano-words.mp3",
            "trackWords": "http://www.taabc.org/check-off-songs/bass/america-the-beautiful/america-the-beautiful-piano-words.mp3"
          }
        },
        {
          "name": "Second Tenor",
          "urls": {
            "pianoWords": "http://www.taabc.org/check-off-songs/second-tenor/america-the-beautiful/america-the-beautiful-piano-words.mp3",
            "pianoSolfa": "http://www.taabc.org/check-off-songs/second-tenor/america-the-beautiful/america-the-beautiful-piano-words.mp3",
            "trackWords": "http://www.taabc.org/check-off-songs/second-tenor/america-the-beautiful/america-the-beautiful-piano-words.mp3"
          }
        },
        {
          "name": "First Tenor",
          "urls": {
            "pianoWords": "http://www.taabc.org/check-off-songs/first-tenor/america-the-beautiful/america-the-beautiful-piano-words.mp3",
            "pianoSolfa": "http://www.taabc.org/check-off-songs/first-tenor/america-the-beautiful/america-the-beautiful-piano-words.mp3",
            "trackWords": "http://www.taabc.org/check-off-songs/first-tenor/america-the-beautiful/america-the-beautiful-piano-words.mp3"
          }
        }
      ]
    }
  ]
}

Songs.Service.ts

export class SongService {
    constructor(private _http: Http) {}

    getAllSongs() {
        return this._http.get('/fixtures/songs.json')
            .map((response: Response) => response.json().songs)
            .toPromise()
            .catch(this.handleError);
    }

    getSongByName(songName:string) {
        return this._http.get('/fixtures/songs.json')
            .map((response: Response) => _.find(response.json().songs, {'name': songName}))
            .toPromise()
            .catch(this.handleError);
    }

Song Component

export class SongsComponent {
    public songs: any;
    public activeSong: any;
    public activeSongURL: any;

    constructor(private _songsService: SongService, private router: Router, private route: ActivatedRoute) {
    }

    ngOnInit() {
        this._songsService.getAllSongs().then(result => {
            this.songs = result;
            console.log('Songs: ', this.songs);
        });
    }

    playSong(songName:string) {
        console.log('clicked song:', songName)

        this._songsService.getSongByName(songName).then(result => {
            this.activeSong = result;
            console.log('active song', this.activeSong);
            this.activeSongURL = this.activeSong.baritone.pianoWords;
            console.log(this.activeSongURL);
        })
    }

    selectSong(songName:string) {
        this.router.navigate(['/song'], songName);
    }
}

HTML Template

<section class="songs container">
    <div class="song col-md-3" *ngFor="let song of songs">
        <h4 (click)="selectSong(song.name)">{{song.name}}</h4>
        <span>Difficulty: {{song.difficulty}}</span>
        <span>Time: {{song.time}}</span>
        <span><strong>Baritone</strong></span>
        <span *ngIf="song.hasPianoSolfa" class="piano-solfa"><i class="fa fa-play-circle-o" aria-hidden="true"></i>Piano Solfa</span>
        <span (click)="playSong(song.name)" *ngIf="song.hasPianoWords" class="piano-words"><i class="fa fa-play-circle-o" aria-hidden="true"></i>Piano Words</span>
        <span (click)="playSong(song.name)" *ngIf="song.hasTrackWords" class="track-words"><i class="fa fa-play-circle-o" aria-hidden="true"></i>Track Words</span>
    </div>
</section>

<section class="audio-player">
    <audio src="{{activeSongURL}}" autoplay controls="controls">
        Your browser does not support the <code>audio</code> element.
    </audio>
</section>

1 Answer 1

2

You could make use of Safe-Navigation-Operator

Looks like you might of had it or been close to having it, shouldn't it be somehting like

<section class="songs container">
    <div class="song col-md-3" *ngFor="let song of songs">
        <h4 (click)="selectSong(song.name)">{{song.name}}</h4>
        <span>Difficulty: {{song.difficulty}}</span>
        <span>Time: {{song.time}}</span>

        <div *ngIf="song?.parts.length > 0">

            <div *ngFor="let part of song?.parts">
                <strong>{{ part.name }}</strong>
                <span class="piano-words" (click)="playSong(song.name)"><i class="fa fa-play-circle-o" aria-hidden="true"></i>Piano Words</span>
                <span class="piano-solfa" (click)="playSong(song.name)"><i class="fa fa-play-circle-o" aria-hidden="true"></i>Piano Solfa</span>
                <span class="track-words" (click)="playSong(song.name)"><i class="fa fa-play-circle-o" aria-hidden="true"></i>Track Words</span>
            </div>

        </div>

        <!-- <span><strong>Baritone</strong></span>
        <span *ngIf="song.hasPianoSolfa" class="piano-solfa"><i class="fa fa-play-circle-o" aria-hidden="true"></i>Piano Solfa</span>
        <span (click)="playSong(song.name)" *ngIf="song.hasPianoWords" class="piano-words"><i class="fa fa-play-circle-o" aria-hidden="true"></i>Piano Words</span>
        <span (click)="playSong(song.name)" *ngIf="song.hasTrackWords" class="track-words"><i class="fa fa-play-circle-o" aria-hidden="true"></i>Track Words</span>
    </div> -->
</section>
Sign up to request clarification or add additional context in comments.

2 Comments

Yes this worked. Didn't know that I could have a nested ngFor referencing the other ngFor
Sure! Glad to help! I may have messed up the way you want them displayed but it looks like I gave you the info you needed.

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.