Search code examples
javascriptrxjsobservable

Getting metadata information from an Observable while executing inside another Observable


I have some song information that I need to add metadata too. I am looking to combine this using one Observable execution (sorry if my terminology is wrong). But I can't get the metadata in the final map

First Attempt:

songsViewData = combineLatest([
    this.songs,
    this.genre,
]).pipe(
    map(([songs, genre]) => { 
        let query = {
            filename: songs[genre],
            song_id_range: 50,
            filenames_included: true
        }

        // This doesn't return the inner object. Just an observable
        return this.getSongData(query).subscribe((metaData) => {
            return (songs[genre]).map((song) => {
                return {
                    id: song,
                    songTitle: metaData[song].songTitle,
                    artistName: metaData[song].artistName
                }
            })
        })
    })
)

Second Attempt:

songsViewData = combineLatest([
    this.songs,
    this.genre,
]).pipe(
    switchMap(([songs, genre]) => {
        let query = {
            filename: songs[genre],
            song_id_range: 50,
            filenames_included: true
        }
        return this.getSongData(query) // This gets the metadata
    }),
    map(([songs, genre, metaData]) => { // I want to access the metadata here

        return (songs[genre]).map((song) => {
            return {
                id: song,
                songTitle: metaData[song].songTitle,
                artistName: metaData[song].artistName
             }
        })
    })
)

Solution

  • You can use a forkJoin in which you wrap both the switchMap and also the other values you need. This only works if this.getSongData completes. Otherwise, take combineLatest instead.

    songsViewData = combineLatest([
        this.songs,
        this.genre,
    ]).pipe(
        switchMap(([songs, genre]) => {
            let query = {
                filename: songs[genre],
                song_id_range: 50,
                filenames_included: true
            }
            return forkJoin([of([songs, genre]), this.getSongData(query)])
        }),
        map(([[songs, genre], metaData]) => { 
            return (songs[genre]).map((song) => {
                return {
                    id: song,
                    songTitle: metaData[song].songTitle,
                    artistName: metaData[song].artistName
                 }
            })
        })
    )