Vue.js The mp3 files have been successfully added to an array, yet the audio remains silent

While coding, I faced an issue that I resolved by doing some research online and tweaking the sample code. As I added more lines of code, I encountered sections that were a bit confusing to me, but I managed to make them work. My main objective is to develop code that can play a sound to alert people waiting for service when it's their turn. The "filenames.value" variable already contains an array list of MP3 files, but currently, I'm having trouble getting any sound to play.

The error message ": onMounted is called when there is no active component instance to be associated with..." indicates that lifecycle injection APIs should only be used within the setup() function during execution. Ensure that any async setup() calls register lifecycle hooks before the first await statement.

<script setup>
import { ref, onMounted, computed } from 'vue';
import axios from 'axios';

const collection1Data = ref([]);
const collection2Data = ref([]);
const finalData = ref([]);
const latestfinalData = ref([]);

const fetchData = async () => {
  const [collection1Response, collection2Response] = await Promise.all([
    axios.get('https://koh-abx.com:50100/onboardshows'),
    axios.get('https://koh-abx.com:50100/onboardlands'),
  ]);
  collection1Data.value = collection1Response.data;
  collection2Data.value = collection2Response.data;
};

onMounted(async () => {
  await fetchData();
  setInterval(async () => {
    await fetchData();
    finalData.value = [];

    collection1Data.value.forEach(doc1 => {
      const matchingDoc = collection2Data.value.find(doc2 => doc1.idshow === doc2.idshow);
      if (matchingDoc) {
        finalData.value.push({
          idshow: doc1.idshow,
          numbershow: doc1.updatedAt > matchingDoc.updatedAt ? doc1.numbershow : matchingDoc.numbershow,
          ab: doc1.updatedAt > matchingDoc.updatedAt ? doc1.ab : matchingDoc.ab,
          updatedAt: doc1.updatedAt > matchingDoc.updatedAt ? doc1.updatedAt : matchingDoc.updatedAt
        });
      } else {
        finalData.value.push({
          idshow: doc1.idshow,
          numbershow: doc1.numbershow,
          ab: doc1.ab,
          updatedAt: doc1.updatedAt
        });
      }
    });

    collection2Data.value.forEach(doc2 => {
      if (!finalData.value.find(doc => doc.idshow === doc2.idshow)) {
        finalData.value.push({
          idshow: doc2.idshow,
          numbershow: doc2.numbershow,
          ab: doc2.ab,
          updatedAt: doc2.updatedAt
        });
      }
    });

    console.log(finalData.value);

    latestfinalData.value = finalData.value.filter(doc => (Date.now() - new Date(doc.updatedAt).getTime()) < 15000);
    console.log(latestfinalData.value);

    const filenames = computed(() => {
      return latestfinalData.value.map(item => {
        const digits = item.numbershow.toString().split('');
        return digits.map(digit => `https://koh-samui.com/sound/${digit}.mp3`);
      });
    });

    console.log(filenames.value);

    const audioRef = ref(null);
    const isPlaying = ref(false);

    onMounted(() => {
      const sounds = filenames.value;

      let currentSound = 0;
      audioRef.value = new Audio(sounds[currentSound]);
      audioRef.value.addEventListener("ended", () => {
        isPlaying.value = false;
        currentSound++;
        if (currentSound < sounds.length) {
          audioRef.value.src = sounds[currentSound];
          audioRef.value.play();
        }
      });

      if (!isPlaying.value) {
        isPlaying.value = true;
        audioRef.value.play();
      }
    });

  }, 2000);
});

</script>

Here is the modified code snippet where I attempted to resolve the issue related to playing the sound:

<script setup>
import { ref, onMounted, computed } from 'vue';
import axios from 'axios';

const collection1Data = ref([]);
const collection2Data = ref([]);
const finalData = ref([]);
const latestfinalData = ref([]);
const sounds = ref([]);
const audioRef = ref(null)
const isPlaying = ref(false)

const fetchData = async () => {
  const [collection1Response, collection2Response] = await Promise.all([
    axios.get('https://koh-abx.com:50100/onboardshows'),
    axios.get('https://koh-abx.com:50100/onboardlands'),
  ]);
  collection1Data.value = collection1Response.data;
  collection2Data.value = collection2Response.data;
};

onMounted(async () => {
  await fetchData();
  setInterval(() => {
    fetchData().then(() => {
      finalData.value = [];

      collection1Data.value.forEach(doc1 => {
        const matchingDoc = collection2Data.value.find(doc2 => doc1.idshow === doc2.idshow);
        if (matchingDoc) {
          finalData.value.push({
            idshow: doc1.idshow,
            numbershow: doc1.updatedAt > matchingDoc.updatedAt ? doc1.numbershow : matchingDoc.numbershow,
            ab: doc1.updatedAt > matchingDoc.updatedAt ? doc1.ab : matchingDoc.ab,
            updatedAt: doc1.updatedAt > matchingDoc.updatedAt ? doc1.updatedAt : matchingDoc.updatedAt
          });
        } else {
          finalData.value.push({
            idshow: doc1.idshow,
            numbershow: doc1.numbershow,
            ab: doc1.ab,
            updatedAt: doc1.updatedAt
          });
        }
      });

      collection2Data.value.forEach(doc2 => {
        if (!finalData.value.find(doc => doc.idshow === doc2.idshow)) {
          finalData.value.push({
            idshow: doc2.idshow,
            numbershow: doc2.numbershow,
            ab: doc2.ab,
            updatedAt: doc2.updatedAt
          });
        }
      });

      console.log(finalData.value);

      latestfinalData.value = finalData.value.filter(doc => (Date.now() - new Date(doc.updatedAt).getTime()) < 15000);
      console.log(latestfinalData.value);
    });

    const filenames = computed(() => {
      return latestfinalData.value.map(item => {
        const digits = item.numbershow.toString().split('');
        return digits.map(digit => `https://koh-abx.com/sound/${digit}.mp3`);
      });
    });

    console.log(filenames.value);
    sounds.value = filenames.value ;
    playSound();

  }, 5000);

});


const playSound = () => {
  let currentSound = 0;
  audioRef.value = new Audio(sounds.value[currentSound]);

  audioRef.value.addEventListener("ended", () => {
    isPlaying.value = false;
    currentSound++;
    if (currentSound < sounds.value.length) {
      audioRef.value.src = sounds.value[currentSound];
      audioRef.value.play();
    }
  });

  if (!isPlaying.value) {
    isPlaying.value = true;
    audioRef.value.play();
  }
};

</script>

Answer №1

Your code is facing an issue where the "onMounted" hook gets called twice, once outside the range function and then inside it. To resolve this issue, you should move the audioRef, isPlaying variables, and the onMounted hook referring to them out of the interval function. This ensures that the hook is registered only once, and both the interval function and the hook can access the variables.

Check out the modified code below:

<script>
import { ref, onMounted, computed } from 'vue';
import axios from 'axios';

const setup = () => {
  // Define reactive references to store data from API requests
  const collection1Data = ref([]);
  const collection2Data = ref([]);
  const finalData = ref([]);
  const latestfinalData = ref([]);

  // Function to fetch data from two API endpoints
  const fetchData = async () => {
    try {
      // Use Promise.all to make concurrent API requests
      const [collection1Response, collection2Response] = await Promise.all([
        axios.get('https://koh-abx.com:50100/onboardshows'),
        axios.get('https://koh-abx.com:50100/onboardlands'),
      ]);
      // Update the reactive references with API response data
      collection1Data.value = collection1Response.data;
      collection2Data.value = collection2Response.data;
    } catch (error) {
      // Log any errors to the console
      console.error(error);
    }
  };

  // Function to combine data from two API endpoints and filter unique values
  const combineData = () => {
    // Combine data from two API endpoints
    finalData.value = [...collection1Data.value, ...collection2Data.value];

    // Use Map to store unique data
    const uniqueData = new Map();
    finalData.value.forEach(doc => {
      const existingDoc = uniqueData.get(doc.idshow);
      if (existingDoc) {
        // If a document with the same idshow exists in the Map, update it with the latest data
        uniqueData.set(doc.idshow, {
          idshow: doc.idshow,
          numbershow: existingDoc.updatedAt > doc.updatedAt ? existingDoc.numbershow : doc.numbershow,
          ab: existingDoc.updatedAt > doc.updatedAt ? existingDoc.ab : doc.ab,
          updatedAt: existingDoc.updatedAt > doc.updatedAt ? existingDoc.updatedAt : doc.updatedAt
        });
      } else {
        // Add the document if a similar idshow is not present in the Map
        uniqueData.set(doc.idshow, {
          idshow: doc.idshow,
          numbershow: doc.numbershow,
          ab: doc.ab,
          updatedAt: doc.updatedAt
        });
      }
    });

    // Convert Map values to an array
    finalData.value = [...uniqueData.values()];
    // Sort the array by updatedAt in descending order and keep only the latest 10 items
    latestfinalData.value = finalData.value.sort((a, b) => a.updatedAt > b.updatedAt ? -1 : 1).slice(0, 10);
  };

  // Call the fetchData function when the component mounts
  onMounted(fetchData);

  // Use computed to monitor changes in collection1Data and collection2Data and invoke combineData
  computed(() => {
    combineData();
  });

  return {
    collection1Data,
    collection2Data,
    finalData,
    latestfinalData,
    fetchData
  };
};

export default {
  setup
};
</script>

I have optimized the code for improved performance

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

What is the best way to include and delete several images on a canvas?

Recently, I've started working with canvas in HTML5 and I'm tasked with creating a paint application. One of the features I need to implement is the ability to dynamically add selected images to the canvas as the mouse moves, and then have the fu ...

Pagination malfunction on AngularJS md-data-table is causing issues

I have been working on a project that involves retrieving data from an API and displaying it in a table. I am using AngularJS and the md-data-table library by Daniel Nagy. Following the setup instructions, I was able to display my data successfully. Howeve ...

I am unable to fast forward or rewind my videos stored on Google Bucket

After developing an e-learning platform using node.js and vue.js, I encountered an issue with my videos stored in GCP buckets. Despite setting up the storage to be private, I noticed that the videos were not allowing users to fast forward or rewind. When a ...

Arranging array elements according to the values in another array

I am working with an array of selections: var selections = ( JSON.stringify($('#approval').select2('data')) ); var selections = JSON.parse("[" + selections + "]"); When I use console.log with selections, the output is: https://i. ...

Using a number input with step increments of 0.01 in AngularJS can result in undefined values for specific inputs

An issue arises when using a specific type of input in angularjs (1.6.1) where the values between 9.03 to 9.05 inclusively return undefined. This problem also occurs with other values like 9.62, 9.63, and 17.31. <input type="number" step="0.01" data-ng ...

Webpack is failing to recognize certain CSS files

My development stack includes Vue.js 2.5.15, Webpack 4.12.0, css-loader 0.28.11, ASP.Net Core 2.1 in Visual Studio 2017. Starting with the Visual Studio asp.net core template project for Vue and Typescript, I prefer to have individual small CSS files with ...

Response from Vimeo's AJAX API

I am having trouble retrieving the AJAX response from Vimeo to extract a thumbnail without using JQuery. Even though I can see the response data in JSON format when I type the response query (http://vimeo.com/api/v2/video/30408418.json) into the browser an ...

Creating a text box that displays an inverted input

Hello, I'm looking to create a text box where if I input 1 then 2, it will display 21. Then if I enter 3, it should show 321. I am currently using Vue.js on my front end. Here is what I have attempted so far: I experimented with methods such as watc ...

Tips for patiently waiting for a series of asynchronous calls to successfully complete

I have a scenario where I am dealing with multiple asynchronous calls that are dependent on each other's success. For example: function1 = () => { /*Some required Logic*/ return fetch("myurl") .then((json) => { functi ...

React Material UI - DataGrid Continuously Distracting Focus Away from Input Field

I'm currently facing an issue with my React web app using Material-UI. The problem arises when I try to type in the search input field, but the focus keeps getting stolen by the Material-UI DataGrid whenever I click on it. Oddly enough, this only occu ...

Populate an HTML table using a JavaScript array containing objects

Greetings, fellow coders! I am new to the coding world and this community, and despite my efforts in searching for a solution, I couldn't find exactly what I was looking for. So, here is my question: I have an array structured as follows: const arr ...

Leveraging JavaScript event handlers within a progress wizard located within an update panel

I need assistance with implementing a password strength meter for a textbox within a wizard control. The issue I'm facing is that the password box does not become visible until step 4, preventing me from registering an event handler onload(). Placing ...

Utilizing the power of async/await to simplify Hapi17 route abstraction

Trying to understand the transition to async/await in Hapi 17 is a bit of a challenge for me. My main focus is figuring out how to modify an abstracted route to make it compatible with async/await. Here is a snippet from my routes\dogs.js file: con ...

What is the best way to bundle an Express server into an Electron application?

Currently in the process of developing an Electron app using vue-cli-electron-builder. My setup includes a local MySQL database and an Express server. I am wondering how to bundle my Express server with the Electron app? The Express server is used for d ...

Trigger Knockout bindings once the ajax request has been completed

In the view, I have the following script: <script> MyObj.initModel(getUrl); $(document).ready(function () { ko.applyBindings(MyObj.viewModel, document.getElementById("someId")); ...

Issue: User is being redirected from "/login" to "/home" due to a navigation guard. This problem arises in the interaction between Vue-router and Firebase authentication

I'm currently working on an app that utilizes Vue.js and Firebase for authentication. I am trying to implement a verification process using the beforeEach method in my router file to ensure that users can only sign in if their displayName matches a sp ...

Tips for updating the value within a textfield in HTML

I am looking to dynamically update the value displayed in my Revenue textfield by subtracting the Cost of Goods from the Sales Price. I have included an image of the current layout for reference, but I want the Revenue field to reflect the updated value af ...

The component is no longer able to locate the imported element when it is being shared

Recently, I imported a component into the shared module in order to use it across 2 different modules. However, upon recompiling the app, an error message appeared stating that the jodit-editor, which is utilized by the shared component, is not recognized ...

Fetching data from MongoDB, loading over 3000 entries and implementing pagination

I'm facing a challenge where I need to display more than 3000 results in an HTML table by fetching MachineID, Username, and Data from my MongoDB. However, I am encountering difficulties when trying to render this data using datatables. The MachineID ...

IE8 triggers automatic download upon receiving JSON response using jQuery

Can you help me make IE8 compatible with this code using jQuery to handle an ajax request that returns data as JSON? $.ajax({ url: formAction, type: 'post', dataType: 'json', data: form, success: ...