Using the ui-router to repeatedly call an AngualrJS directive

I've encountered an issue with my HTML audio player in AngularJS. When the page is refreshed, everything works perfectly - I can set the source and play audio without any problems. However, if I navigate to another state in the app and then try to load/play the audio, multiple instances of the audio start playing simultaneously. This behavior repeats for each state change, leading to multiple instances of the audio playing at once.

Why is the audio player initializing repeatedly? How can I prevent this and keep it active as I switch between states without interrupting playback?

Here is a snippet of the relevant code. The view footer.html contains the directive and player, which are included by each state.

index.html :


  ...
  <div style="clear:both"></div>

  <div ui-view="footer"></div>
</body>

app.js :

.state('audiolist', {
      url: '/audiolist/',
      views: {
        sideNav: {
          templateUrl: 'views/sideNav.html',
          controller: 'sideNavController'
        },
        header: {
          templateUrl: 'views/header.html',
          controller: 'headerController'
        },
        content: {
          templateUrl: 'views/list.main.html',
          controller: 'listController as content'
        },
        footer: {
          templateUrl: 'views/footer.html',
          controller: 'apController as ap'
        }
      })
    ...
    .state('saveditems', {
      url: '/saveditems/',
      views: {
        sideNav: {
          templateUrl: 'views/sideNav.html',
          controller: 'sideNavController'
        },
        header: {
          templateUrl: 'views/header.html',
          controller: 'headerController'
        },
        content: {
          templateUrl: 'views/saveditems.main.html',
          controller: 'savedItemsController as content'
        },
        footer: {
          templateUrl: 'views/footer.html',
          controller: 'apController as ap'
        }
      }
...

footer.html

    <div class="audioplayer">
      <!-- Audio Player -->
      <hls-player id="player" playlist="{{ap.tracks}}"></hls-player>
...

directives/hlsPlayer.js

module.directive('hlsPlayer', function ($window, $templateRequest, $compile, $http, $rootScope) {
return {
    restrict: 'AE',
    link: function ($scope, element, attrs) {
        $templateRequest("views/playerTemplate.html").then(function (html) {
        // player functions 
        ... 
        // play function 
           ...
           console.log("manifest loaded, found " + data.qualities + " quality level");
           console.log("audio loaded and playing");
    ...

playerTemplate.html

...
 <audio autobuffer preload="metadata" src="" id="radio" class="hidden" preload="none"></audio>
...

Answer №1

Whenever the state is modified, AngularJS triggers a reinitialization of the controllers. The hlsPlayer directive shares the scope with the controller, causing the link function to be executed again.

To gracefully stop the player and conclude the directive's tasks, you can utilize $on "$destroy".

element.on('$destroy', function () {
     // halt/terminate the player operations here
});

On a side note, it is recommended to use a service for storing the player instance instead of initializing the player within directives.

Answer №2

To address the issue, I found a solution that may not be applicable in all scenarios. I decided to relocate the HTML5 player outside of the directive template and instead place it directly in the main index.html page. This approach proved effective for handling persistent audio in Angular, allowing me to still manage, control, and display a timeline by referencing the audio element as needed.

Here is how it was implemented:

<audio id="mediaPlayer" autobuffer preload="metadata" src="" id="radio" class="hidden" preload="none"></audio>

Within the directive:

return {
    restrict: 'AE',
    link: function ($scope, element, attrs) {
 $templateRequest("views/playerTemplate.html").then(function (html) {
            var template = angular.element(html);

            element.html(template);
            $compile(element.contents())($scope);

            var elem = angular.element(document.querySelector('#mediaPlayer'));
            var audio = elem[0];

            $scope.play = function () {               
                    audio.play();
                }

In the playerTemplate.html file:

<a type="button" ng-click="played=!played; played ? play() :stop();"><i
                ng-class="played?'nav-btn-play fa fa-pause-circle-o':'nav-btn-play fa fa-play-circle-o'"></i></a>

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

Expand or collapse Angular Material Accordion depending on selected Radio button choice

Is it possible to use a mat-accordion with radio buttons where each panel expands only when its corresponding radio button is selected? I have the radio buttons functioning correctly, but the panels are expanding and collapsing with every click rather than ...

The PUT rest service does not function in AngularJS version 1.0.8

I am facing an issue with my AngularJS application that has a CRUD Rest service. While the Create, Read, and Delete methods are functioning properly, the PUT method is not working. I have searched on Stackoverflow and found similar problems with accepted s ...

Randomizer File Name Maker

I was questioning the behavior of Multer Filename. If Multer stores files with random filenames, is there a possibility of two files having the same name in Multer? In other words, if I am storing files from a large number of users, could the filenames e ...

methods for removing json comments using javascript

Looking to remove JSON comments using JavaScript? I believe a regular expression would be the most efficient method. { "field": { // comments "n": 1 /* multi-line ... comments */ }, ...

The 'substr' property is not found in the type 'string | string[]'

Recently, I had a JavaScript code that was working fine. Now, I'm in the process of converting it to TypeScript. var ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; if (ip.substr(0, 7) == "::ffff ...

Switch out the URL in npm's build process

While developing, I am using a mock REST service but for the public release, I intend to switch to a real backend. Is there a method to update the endpoint URL during the npm build process? ...

Variable Returned by AJAX

I am attempting to send a variable using a select box via POST method, then use AJAX to submit the data and finally leverage that variable on the original page to update SQL queries. Below is the code snippet I currently have: <script type="text/j ...

Pinia has not been instantiated yet due to an incorrect sequence of JavaScript file execution within Vue.js

I'm currently developing a Vue.js application using Vite, and I have a Pinia store that I want to monitor. Below is the content of my store.js file: import { defineStore } from 'pinia'; const useStore = defineStore('store', { st ...

Accessing store in Vue, the getter function returns a value representing whether the user is currently logged

I have the user state stored in my Vue store, but when I try to access it like this: let isLoggedIn = store.getters.isLoggedIn Instead of getting a simple true or false, I see this in the console: ƒ isLoggedIn (state) { return state.user ? true : false ...

Issue encountered while attempting to save the date to a json file

While working on my code to directly print the date from index.js into data.json, I encountered an error stating that data is not defined. This is what I have done so far: Ran npm init Installed jsonfile using npm i jsonfile index.js const json ...

Is it true that IE does not support passing callback parameters to setTimeout()?

When I used the js setTimeout function in my code, it worked perfectly in Firefox by reloading within seconds. However, the same code did not work in IE. I tried changing the method to 'POST', but received an error stating that the request was no ...

Explanation for the strange floating math in JavaScript - Understanding the IEEE 754 standard for laymen

When it comes to JavaScript and working with floating point numbers, I always feel a bit lost. Dealing with decimals makes me nervous because I'm never quite sure what's happening behind the scenes. If only I understood how the IEEE 754 standard ...

Issue with updating dropdown values in real-time in React

I am a beginner with React and I have a question regarding fetching dropdown values from the backend. Despite using async-await functions, the list is not getting populated with items. Any assistance in this matter would be greatly appreciated. Here is th ...

An issue related to AngularJS and the injection of ui-bootstrap components has been encountered

I'm encountering an issue with injection errors in my code, and unfortunately, the debugger in Firefox isn't providing much help. Here are snippets of the code: This is the Controller file causing the error: App.controller('ModalInstanceCt ...

Implementing custom CSS styles for HighCharts API pie chart drilldown labels

I successfully created a pie chart using highcharts and configured the chart with the following options: chart: { type: 'pie', }, In order to change the width of the text on the chart, I added the following options which force e ...

One of the great features of Next.js is its ability to easily change

At the moment, my dynamic path is configured to display events by their ID [id].js localhost:3000/event/1 But I would like it to be structured as follows: localhost:3000/city/date/title. All of this information is available in the events database, but I&a ...

Managing active dropdown menus in VueJS

I'm having trouble figuring out why my navigation menu and method to open subitems on click are not working correctly. [![dropdown_menu][1]][1] new Vue({ el: '#app', data: { //menu "menu_title": "a", "child_ro ...

The process of implementing server-side rendering for React Next applications with Material-ui using CSS

I have developed a basic React application using Next.js with an integrated express server: app.prepare() .then(() => { const server = express() server.get('/job/:id', (req, res) => { const actualPage = '/job' const ...

Discover the process of retrieving an element by its ID when dealing with dynamically generated IDs in AngularJS

I am creating a list using the following code snippet: <div ng-repeat="list in fileUploadList"> <div id="{{list}}Upload"></div> </div> Within the controller, I need to retrieve the element by ID, so I am utilizing this line of ...

Please identify the path of chromedriver for selenium-standalone

I've encountered an issue when trying to initialize the selenium-standalone server (https://www.npmjs.com/package/selenium-standalone). The error message I receive is as follows: 14:19:09 /usr/local/lib/node_modules/selenium-standalone/bin/selenium-s ...