Reactivity in audio control tag with v-bind

I’ve got a simple component that takes one parameter: a url to a music file:

<template>

        <div v-if="isFileATrack()">
            <h4>Playing: {{ track }}</h4>
            <div class="ghettoplayer">
                <audio controls >
                    <source v-bind:src="track">
                    Your browser does not support the audio element.
                </audio>
            </div>
        </div>

</template>

<script>

    export default {
        props: ['track'],
        methods: {
            isFileATrack: function() {
                return this.track.endsWith('.mp3') || 
                       this.track.endsWith('.wav') || 
                       this.track.endsWith('.aif') ? true : false
            }
        }
    }
</script>

<style>
</style>

When ‘track’ updates everything works fine the first time. Then, the next time ‘track’ updates just the

tag updates. The v-bind does not.

This updates great:

            <h4>Playing: {{ track }}</h4>

This does not update:

                    <source v-bind:src="track">

What am I doing wrong? How can I force the v-bind to update the audio div?
Thanks!

Try setting up a $watch of the track prop, and on change .load() the source. You need to tell the browser the source has changed.

<template>
    <div v-if="isFileATrack()">
        <h4>Playing: {{ track }}</h4>
        <div class="ghettoplayer">
            <audio ref="player" controls>
                <source v-bind:src="track">
                Your browser does not support the audio element.
            </audio>
        </div>
    </div>

</template>

<script>
    export default {
        props: ['track'],
        mounted: function () {
            this.$watch('track', () => {
                this.$refs.player.load()
            })
        },
        methods: {
            isFileATrack: function() {
                return this.track.endsWith('.mp3') || 
                       this.track.endsWith('.wav') || 
                       this.track.endsWith('.aif')
            }
        }
    }
</script>

https://jsfiddle.net/v2fneLz2/3/

2 Likes

Thanks, but no love. Maybe this is a bug?

I cant get $refs to bind to the element. I’ve tried ref=“src”, and id="src"
Then tried to bind to it with:

this.$el.src.load()

and

this.$refs.src.load()

accordingly.

errors:

accepter.js:9930 [Vue warn]: Error in watcher "track" 
accepter.js:15110 Uncaught (in promise) TypeError: Cannot read property 'load' of undefined(…)

So I thought maybe its too early in the vue lifecycle? I tried to start the watcher in “mounted”, but get same error.

calling .load() seemed so hopeful :slight_smile:

A quick fiddle shows v-bind+src work just fine for me. Maybe an error in your logic?

Had to make a second account to message ahah

@phanan The problem he has, is you need to tell the browser the source has changed, for example: https://jsfiddle.net/v2fneLz2/2/

@ryanrca https://jsfiddle.net/v2fneLz2/3/
You can add .play() after load if you want it to autoplay after changing the source.

Oh, I get it now. In such a case then yes, something like a watch should fix the problem.
Btw @avitex2 what’s wrong with your other account?

There is a 10 post limit for new users on the forum which I reached, would have had to wait till tomorrow to answer the question. There is also a limit on sending users messages that I reached :stuck_out_tongue:

Thanks guys,
I’m convinced this is a good solution, but I’m blocked by a new issue:

I hope this is a real issue and not “I’m just a n00b”.

Okay, this issue is resolved. Thanks for helping this n00b out. Here is the final code that works:

<template>

    <div class="panel accepter-player">
        Track URL:
        <p>{{ getTrackName }}</p>
        <div class="ghettoplayer">
            <audio ref="player" controls>
                <source v-bind:src="getTrackName" v-if="isFileATrack">
                Your browser does not support the audio element.
            </audio>
        </div>
    </div>

</template>

<script>

    export default {
        props: ['track'],
        mounted: function () {
            this.$watch('track', function() {
                this.$refs.player.load()
            });
            console.log(this.$refs)
        },
        computed: {
            isFileATrack: function() {
                return this.track.endsWith('.mp3') || 
                       this.track.endsWith('.wav') || 
                       this.track.endsWith('.aif') ? true : false
            },
            getTrackName: function() {

                return this.isFileATrack ? this.track : '-- none --' 
            }
        }
    }

</script>

<style lang="sass">
</style>

The issue before was, the ref= was INSIDE the v-if, so it wasn’t rendered on page load. Hence $refs was undefined.
I am a n00b!

@ryanrca Glad we could help and that’s working now

thanks its work for me :innocent: