Using Vue3 to create a dynamic reference in a computed status, allowing for the repetition of a player multiple times in a table along with a play/pause

On the Vue3 page below, I have successfully integrated a player that displays a "play" icon when the player is stopped and a "pause" icon when it's playing.

Now, my goal is to allow the player to repeat n times by placing it in a table.

The challenge I am facing is that I currently use the "ref" of the player ("audioPlayer") as input for the "compute". When I repeat the player n times, I cannot hard-code the player's ref, so I need to dynamically evaluate the "isPlaying" status for the audioPlayer in each respective row.

I have attempted to utilize methods and higher-order functions (as mentioned here), but I haven't been able to find a solution.

Any guidance on this matter would be greatly appreciated.

Thank you.

P.s. The example provided works fine; however, I am struggling with inserting the player within the repetition loop, as I can't seem to compute the isPlaying property correctly depending on which row I'm in.

<template>
  <div v-for="index in 3" :key="index"> 
    {{ index }}. Player should be placed here <p></p> <!-- <<<<<<<<< The player should repeat in this section -->
    ----------------------------------
  </div>

  <div v-if="!isPlaying" class="audio__play-start" @click.stop="this.$refs.audioPlayer.play"><q-icon name="play_circle"></q-icon></div>
  <div v-else class="audio__play-pause" @click.stop="this.$refs.audioPlayer.pause"><q-icon name="pause_circle"></q-icon></div>
  
  <div>
    <audio-player
      ref="audioPlayer"
      :audio-list="['./api/soundfiles?path=/tmp&filename=rock.mp3']"
      theme-color="black"
      :show-prev-button="false"
      :show-next-button="false"
      :show-play-button="false"
      :show-volume-button="false"
      :show-playback-rate="false"
    />
  </div>
</template>

<script lang="ts">
import { ref, computed } from 'vue';

export default {
  
  setup () {
    const audioPlayer = ref(Object)
    const isPlaying = computed(() => {  
      return audioPlayer.value.isPlaying
    })

    return {
      audioPlayer,
      isPlaying
    }
  },

}
</script>

Answer №1

<template>
  <div v-for="num in 3" :key="num"> 
    {{ num }}. Insert player content here <p></p> <!-- <<<<<<<<< The player should be displayed repeatedly here -->
    ----------------------------------
  </div>

  <div v-if="!isPlaying[num]" class="start-audio__play"  @click.stop="playerRefs[num].play(),isPlaying[num]=true"><q-icon name="play_circle"></q-icon></div>
  <div v-else class="pause-audio__play" @click.stop="playerRefs[num].pause(),isPlaying[num]=false"><q-icon name="pause_circle"></q-icon></div>
  <div>
    <audio-player
      :ref="(el)=>setPlayerRef(el, num)"
      :audio-list="['./api/soundfiles?path=/tmp&filename=rock.mp3']"
      theme-color="black"
      :show-prev-button="false"
      :show-next-button="false"
      :show-play-button="false"
      :show-volume-button="false"
      :show-playback-rate="false"
    />
  </div>
</template>

<script lang="ts">
import { ref, computed } from 'vue';

export default {
  
  setup () {
  const playerRefs= {}
  const setPlayerRef = (el, key) => {
     if (el) {
        playerRefs[key] = el
      }
   }

    const isPlaying = ref({1:false,2:false,3:false})
    return {
      isPlaying,
      setPlayerRef,
      playerRefs
    }
  },

}
</script>

Answer №2

Shoutout to @moon and @yoduh for the help.

@yoduh, your solution was heading in the right direction, but I encountered some additional events (like interacting with the "progress bar") that complicated things. Using the "isPlaying" variable to track playback status didn't quite cut it for me.

In the end, I took advice from @yoduh and implemented a method that did the trick. Appreciate both of you for guiding me through this challenge.

Here's how I tackled repeating elements with v-for:

<template>
  <div v-for="index in 3" :key="index"> 
    {{ index }} ---------------------------------- <p></p> 
    {{ isPlaying(index) }}

    <p></p>
  <div v-if="!isPlaying(index)" class="audio__play-start"  @click.stop="audioPlayerRefs[index].play()"><q-icon name="play_circle"></q-icon></div>
  <div v-else class="audio__play-pause" @click.stop="audioPlayerRefs[index].pause()"><q-icon name="pause_circle"></q-icon></div>
  <div>
    <audio-player
      ref="audioPlayerRefs"
      :audio-list="['./api/soundfiles?path=/tmp&filename=rock.mp3']"
      theme-color="black" :show-prev-button="false" :show-next-button="false" :show-play-button="false" :show-volume-button="false" :show-playback-rate="false" :show-play-loading="false"
    />
  </div> </div>
</template>

<script lang="ts">
import { ref } from 'vue';
import AudioPlayer from '@liripeng/vue-audio-player'
export default {
  
  setup () {
  const audioPlayerRefs = ref([Object])
    return {
      audioPlayerRefs
    }
  },

  methods: {
    isPlaying(index) {
      if (this.audioPlayerRefs[index] == undefined){return false}
      return this.audioPlayerRefs[index].isPlaying
    }
  }

}
</script>

Update:

To complete the picture, I had to make adjustments since I wanted to use the player within a quasar table. Unlike regular v-for loops, Quasar doesn't return the player reference as an array, so I had to modify my approach.

I made the tweaks below based on inspiration from @moon's previous solution, employing function refs.

Both options work depending on the scenario - the initial one for standard v-for applications, and the revised version for quasar tables.

Sharing this in case it helps someone else facing a similar challenge.

Handling repetitive elements within a quasar table:

<template>
  <q-table
    title="Wishes"
    :rows="[{id:10},{id:20},{id:3},{id:6},{id:8}]"
    row-key="id"
    grid
    hide-header
  >
    <template v-slot:item="props">
      <div class="q-pa-xs col-xs-12 col-sm-6 col-md-4 col-lg-3 grid-style-transition" :style="props.selected ? 'transform: scale(0.95);' : ''" >
        <q-card bordered flat :class="props.selected ? ($q.dark.isActive ? 'bg-grey-9' : 'bg-grey-2') : ''">

          <div v-if="!isPlaying(props.row.id)" class="audio__play-start"  @click.stop="audioPlayerRefs[props.row.id].play()"><q-icon name="play_circle"></q-icon></div>
          <div v-else class="audio__play-pause" @click.stop="audioPlayerRefs[props.row.id].pause()"><q-icon name="pause_circle"></q-icon></div>
          <div>
            <audio-player
              :ref="(el) =>setAudioPlayerRef(el, props.row.id)"
              :audio-list="['./api/soundfiles?path=/tmp&filename=rock.mp3']"
              theme-color="black" :show-prev-button="false" :show-next-button="false" :show-play-button="false" :show-volume-button="false" :show-playback-rate="false" :show-play-loading="false"
            /> 
          </div>
  
        </q-card>
      </div>
    </template>
  </q-table>
  <a @click="console.log(Object.keys(audioPlayerRefs).length);console.log(audioPlayerRefs)">Click me</a>
</template>

<script lang="ts">
import { ref } from 'vue';

export default {
  
  setup () {
    const audioPlayerRefs = ref({})
    const setAudioPlayerRef = (el, key) => {
      if (el) {
        audioPlayerRefs.value[key] = el
      }
    }   

    return {
      setAudioPlayerRef,
      audioPlayerRefs
    }
  },

  methods: {
    isPlaying(rowIndex) {
      if (this.audioPlayerRefs[rowIndex] == undefined){return false}
      return this.audioPlayerRefs[rowIndex].isPlaying
    }
  }
}
</script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Should private members be kept confidential during program execution?

While Typescript's "private" members may not be truly private at runtime, traditional closures maintain the privacy of their members. Is there value in ensuring that private members remain private during runtime? ...

Incorporating @nuxtjs/axios with @nuxtjs/composition-api and nuxt 2: A Comprehensive Guide

Looking to integrate the https://www.npmjs.com/package/@nuxtjs/axios package in conjunction with the Nuxt 2.17 and (@nuxtjs/composition-api) plugin. However, the usage of this.$axios is not functioning as expected. I've attempted to inject it without ...

The mark-compacts were not efficient enough, they approached the heap limit and as a result, the allocation failed. The JavaScript

Currently working with Angular version 7.2 and encountering an issue when running ng serve: FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory What does this error mean? How can it be resolved? The ...

Using the Javascript function getElementById to retrieve user input for passing a RSS FeedURL

I've been working on creating a basic form where users can input a Feed URL and see the contents displayed on the HTML page. For testing purposes, I have used "https://jquery-plugins.net/rss" as the feedUrl, and it has been functioning normally. This ...

Filtering data from Arduino using web serial communication

My setup consists of an Arduino kit connected to a webserial API that sends data to an HTML div identified by the id 'target'. Currently, all the data is being logged into one stream despite having multiple dials and switches on the Arduino. Th ...

State change shows the previous and current values simultaneously

I've been working on updating the values of initUsers on the DOM. The initial state values work fine, but when I try to update initUsers, it displays different values than expected. Essentially, entriesNum receives a number as an event and changes th ...

What is the proper way to assign an array of objects to an empty array within a Vue component?

I'm currently working on my first Laravel project using Vue components. My setup includes Laravel 8.x and Vue 2.x running on Windows 10. I came across a helpful video tutorial that I'm trying to follow, but some aspects aren't quite working ...

The mouse scurries away once the div height has been adjusted

How can I make the height of #header change when hovering over #hoverme, and then revert back to its original height when the mouse leaves #hoverme? If anyone knows a solution, please check out my jsfiddle as it's not working as I intended. Here is ...

What is the proper way to utilize "three.module.js"?

I am currently learning how to utilize modules and decided to start with a simple example. However, I encountered an issue where the script does not want to run. I must be missing something crucial, but I can't seem to figure out what it is. I have tr ...

Is there any specific value that will always result in a true comparison in JavaScript?

Is there a special JavaScript value that will always make a comparison true? For example using the less than operator: true < 10 true false < 10 true null < 10 true Or using the greater than operator: true > 10 ...

What steps can be taken to resolve the issue of the Cannot POST /index.html error?

Here is an example of a calculator app created using HTML and Javascript. Upon running the program with nodemon and accessing localhost:3000, pressing the submit button triggers an error on Google Chrome. [nodemon] starting `node calculator.js` Server sta ...

When attempting to retrieve JSON data for the second time, AJAX fails to fetch the information

After successfully sending an Ajax request to a php file and receiving a JSON array of the submitted data, I encountered an error on the second attempt. The error message reads: SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of the JSO ...

Ways to eliminate a specific Chip from Autocomplete outside of material UI

Seeking assistance with displaying selected values as <Chip /> outside of the <TextField /> in <Autocomplete />. The issue lies in deleting these chips and updating the selected prop within <Autocomplete />. Any suggestions or solut ...

Updating comment content using Ajax

I am in the process of using Ajax to insert my comment content. However, I seem to be facing some issues with the comment_add.php page. I was hoping someone could review it for me. While I have successfully obtained the streamid as checked in firebug, no ...

"Obtaining a three.js sprite within a Verold script - the ultimate guide

Greetings fellow users of stack overflow! I've recently been experimenting with the world editor known as verold, based on three.js. The features it offers are quite impressive, but I've encountered an issue with the scripting aspect. My curren ...

Exploring Angularjs: Navigating to a particular element within ng-repeat

I created a custom directive that generates a list of buttons using ng-repeat: HTML <div ng-controller="toggleButtonController" ng-init="init()" id="parent"> <div ng-repeat="btn in setting" style="display:inline"> <button class ...

Retrieve the most recent information from the API using axios and React hooks

I have access to an API that provides data, but I am only interested in the most recent information. The newest data is always located at the end of the dataset. For instance, if there are 50 points of data, the latest would be number 50. Can someone adv ...

What could be causing my bootstrap-switch to malfunction?

Here is the snippet of code I am working with: jQuery.each($('.onoffswitch-checkbox'), function(i, slotData) { console.log($(slotData).bootstrapSwitch('state')) }) <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1 ...

When using a variable to fetch data in JSON, an undefined error occurs. However, if a hardcoded index

I am facing an issue while trying to extract and manipulate JSON data from a file for an application I am developing. When looping through the data, I encounter an undefined error that seems to indicate a missing property in the JSON object when accessing ...

Creating a new object in an empty array within my profile model (mongodb/mongoose) is simple. Just follow these steps to successfully add a

Presenting my Profile model: const ProfileSchema = new mongoose.Schema({ user: { type: mongoose.Schema.Types.ObjectId, ref: "User", }, company: String, website: String, location: String, status: { type: String, require ...