0

I want to implement a music player using Vue and the Vuex Store. I want that the next song starts playing when the current one ends. In normal js, I'd just use:

curr_track.addEventListener("ended", playNext)

where playNext would be a function I defined inside the same main.js file. When using Vue js and Vuex store, however, I can't do it the same. Any suggestions? I tried to pass the mutations function playNext inside of my store, but it did not work. Also, when calling

state.curr_track.duration = track.duration

I get the error:

Uncaught TypeError: Cannot set property duration of #<HTMLMediaElement> which has only a getter

How do I fix this? Thank you

The code is the following:

import { createStore } from 'vuex'

const store = createStore({
    state() {
        return {
            curr_track: null,
            track_list: null,
            isPlaying: false,
        }
    },

    mutations: {

        setTrackList(state, tracks) {
            state.track_list = tracks
        },
        /**
         * Load the track and play it
         * @param state - the state object
         * @param state - the state object
         */
        loadTrack(state, track) {
            if (state.isPlaying) {
                state.curr_track.pause()
            }

            // get track info
            state.curr_track = new Audio()
            state.curr_track.id = track.id
            state.curr_track.src = track.file
            state.curr_track.name = track.name
            state.curr_track.artists = track.artists

            // TODO: fix duration
            // state.curr_track.duration = track.duration
            state.curr_track.album_name = track.album.name
            state.curr_track.album_cover = track.album.img_cover
            state.curr_track.load()

            // play track
            this.commit('playTrack')
            // TODO FIX
            state.curr_track.addEventListener("ended", function() {
                // if (state.track_list == null) {
                //     alert('Please select a track first')
                //     return []
                // }
                // if (state.track_list[state.track_list.length - 1]['id'] == state.curr_track.id) {
                //     console.log('last track, go to first')
                //     this.commit('loadTrack', state.track_list[0])
                // } else {
                //     console.log('go to next track')
                //     let curr_idx = state.track_list.findIndex(track => track.id == state.curr_track.id)
                //     this.commit('loadTrack', state.track_list[curr_idx + 1])
                // }
            })
        },
        playTrack(state) {
            // play loaded track
            if (state.curr_track != null) {
                state.curr_track.play();
                state.isPlaying = true;
            } else {
                alert('Please select a track first')
            }


        },
        pauseTrack(state) {
            // Pause the loaded track
            state.curr_track.pause();
            state.isPlaying = false;
        },
        setVolume(state, value) {
            // Set the volume
            state.curr_track.volume = value
        },

        /**
         * Play the next track: if the current track is the last track in the track list, then load the first track in the
         * track list. Otherwise, load the next track in the track list
         * @param state - the state object
         */
        playNext(state) {
            if (state.track_list == null) {
                alert('Please select a track first')
                return []
            }
            if (state.track_list[state.track_list.length - 1]['id'] == state.curr_track.id) {
                console.log('last track, go to first')
                this.commit('loadTrack', state.track_list[0])
            } else {
                console.log('go to next track')
                let curr_idx = state.track_list.findIndex(track => track.id == state.curr_track.id)
                this.commit('loadTrack', state.track_list[curr_idx + 1])
            }
        },

        /**
         * Play the previous track: if the current track is the first track in the track list, then load the last track in the
         * track list. Otherwise, load the previous track in the track list
         * @param state - the state object
         */
        playPrevious(state) {
            if (state.track_list[0]['id'] == state.curr_track.id) {
                console.log('first track, got to last one')
                this.commit('loadTrack', state.track_list[state.track_list.length - 1])
            } else {
                console.log('go to previous track')
                let curr_idx = state.track_list.findIndex(track => track.id == state.curr_track.id)
                this.commit('loadTrack', state.track_list[curr_idx - 1])
            }
        }
    },
    getters: {
        getIsPlaying(state) {
            return state.isPlaying
        },
        getCurrTrack(state) {
            return state.curr_track
        }

    },
    actions: {

    }
})

export default store
Alex
  • 11
  • "I can't do it the same" - why? – Estus Flask Dec 16 '22 at 16:04
  • because playTrack is a mutator function inside the store and I didn't find a way to pass a mutator function of the store as function to the ```addEventListener()``` (which is also called 'inside' of the store). Do you have an idea on how to do it? – Alex Dec 16 '22 at 16:12
  • What's the problem with this? The only one I see is that callback function is used incorrectly, see https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback . And you need to keep a reference to this function in a store to do removeEventListener before adding a new one – Estus Flask Dec 16 '22 at 16:59

0 Answers0