How to pause player in component in another instance of the component



  • I’ve added vue-plyr to my little SPA to let it play audio files from a playlist of podcast episodes, and I have everything figured out and working except for one thing.

    The player is in a component that appears once on the page for each instance of the playlist. So with a playlist of 25 episodes, there are 25 instances of the component on the page.

    What I can’t figure out is if one instance is playing an episode, and the user clicks another episode’s player in a separate instance, how to tell the first episode in the first instance to stop playing.

    Vue-plyr wants me to fire this.player.pause within the player component to pause the player, but of course the current “this” refers to the newly playing player instance, not to the old one.

    I’ve declared a property called oldPlay to keep track of the id of the old player instance, but I cannot figure out how to get the old instance to receive the oldPlay property after the new player instance starts playing and apply this.player.pause within the old player instance.

    Here’s what I have so far.

    playlist (parent) vue page:

    <template>
      <q-page class="flex-center">
          <div v-for="item in feed" :key="item.id">
            <h6>{{ item.title }}</h6>
            <p>{{ item.description }}</p>
            <player
              :mp3="item.mp3"
              :id="item.id"
              :oldPlay="oldPlay"
              @play="play(item.id)"
            ></player>
            <hr>
          </div>
      </q-page>
    </template>
    
    <script>
    export default {
      data() {
        return {
          feed: this.$feed,
          oldPlay: 0
        }
      },
      components: {
        'player' : require('components/Player.vue').default
      },
      methods: {
        play(id){
          this.oldPlay = id
        }
      }
    }
    </script>
    

    player (child) component vue page:

    <template>
        <vue-plyr ref="plyr">
          <audio preload="none">
            <source :src="mp3" type="audio/mp3" />
          </audio>
        </vue-plyr>
    </template>
    
    <script>
    export default {
      name: 'Player',
      props: {
        mp3: String,
        id: Number,
        oldPlay: Number
      },
      computed: {
        player() {
          return this.$refs.plyr.player
        }
      },
      data(){
        return{
          play: false
        }
      },
      mounted(){
        this.playIt()
     },
      methods: {
        playIt(){
          this.player.on('play', () => this.$emit('play'))
        }
      }
    }
    </script>
    

    Help!



  • Use refs attribute, in your parent. You’ll be able to call child methods.

    https://vuejs.org/v2/api/#ref



  • @jraez Okay, I can see the potential value of refs in this case, but how would I apply them in this case? I need to in some way tell the old instance to fire this.player.pause. How could I use refs to accomplish this?



  • I can’t write the whole code for you but here something to starts with.

     <player
              :mp3="item.mp3"
              :ref="`player_${item.id}`"
              :id="item.id"
              :oldPlay="oldPlay"
              @play="play(item.id)"
            ></player>
    
     play (id){
       if (this.oldPlay) {    
       this.$refs[`player_${id}`].stop()
      }
      this.oldPlay = id
     }
    


  • @jraez Okay, thanks for the start. I’m confused by this note in the docs: “You should avoid accessing $refs from within templates or computed properties.” Isn’t that what we’d be doing here, accessing a ref from within a template?



  • Nop, you access through a component’s method. This is the basic use-case.

    In a template, it’s like writing :

    <template>
     <div ref="one">test</div>
     <div>{{$refs.one.$el.html}}</div>
    </template>
    

    in computed, it’s all that belongs to your component computed() property

    export default { 
     name: "MyComponent",
     computed () {
        test ()  {
          console.log(this.$refs.one.$el.html)
        }
      }
    }
    

Log in to reply