6
votes

On a click function I have the option of playing audio.

The click is only fired once (after I added .off(), which I seem to have to do for every click event because I think there's something I fundamentally don't get about how javascript works) but the function added to the "ended" listener shows it is firing the number of times the button has been clicked. I presume .play() is also being fired multiple times.

These need to be inside the click event to get the id so how do I stop these kinds of things from happening, here and elsewhere when using js? Adding event.stopPropagation(), event.bubbles = false and .off() everywhere seems unnecessary (and in this case doesn't make a difference anyway).

$('.button').off().on('click', function(event){
    event.stopPropagation();
    event.bubbles = false;
    var id = $(this).attr('id')
    if ($(this).hasClass('hasAudio')) {
        document.getElementById('audio_'+id).play();
        document.getElementById('audio_'+id).addEventListener("ended", function(){
            console.log("ended");
        });
    }
});
5
Because you are adding the event listener each time you click on the button. - Nandu Kalidindi

5 Answers

1
votes

Move the ended event outside the click event,you are registering the event each time you click on the button

$('.button').on('click', function(event){
    var id = $(this).attr('id')
    if ($(this).hasClass('hasAudio')) {
        document.getElementById('audio_'+id).play();

    }
});
$('[id^="audio_"]').on("ended", function(){
    console.log("ended");
 });
1
votes

Each time you click on the button a new event listener will be added to the ended event. To prevent that you can try defining the callback function before hand. That will prevent your event listener to be added in the event loop over and over.

An anonymous function has no signature, hence when you define the event with it, it will think that this is supposed to be a new event listener and invokes it multiple times. Check the working snippets to see the difference. Type something in the input box to see what is happening.

If this is confusing then removeEventListener can be the next option.

function ended(event){
    console.log("ended");
}

$('.button').off().on('click', function(event){
    event.stopPropagation();
    event.bubbles = false;
    var id = $(this).attr('id')
    if ($(this).hasClass('hasAudio')) {
        document.getElementById('audio_'+id).play();
        document.getElementById('audio_'+id).addEventListener("ended", ended);
    }
});

var input = document.getElementById('some');


function callback(event) {
  console.log("PRINT");
}

input.addEventListener("keyup", callback)

// input.removeEventListener("keyup", callback)

input.addEventListener("keyup", callback)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="some" value="" >

Anonymous function as callback

var input = document.getElementById('some');

input.addEventListener("keyup", function(event) {
  console.log("PRINT");
})

// input.removeEventListener("keyup", callback)

input.addEventListener("keyup", function(event) {
  console.log("PRINT");
})
<input id="some" value="">
0
votes

This fails because, every time you click the function, you add a new event listener to the button.

        document.getElementById('audio_'+id).addEventListener("ended", function(){
        console.log("ended");

This is repeatedly adding the event listener to the button.If you need this inside the click event, check to see whether it exists already. If it does, don't add it again.

0
votes

Use global flag which defines if you want to pause or play. and also use preventDefault (in case of any inline click event used).

0
votes

You have to remove the registered event listener after your task is completed.

document.getElementById('audio_'+id).removeEventListener("ended", function(){
        console.log("ended");
    });

Or what you can do is that move the logic for registering event listener outside the click event listener. Like this the event will be registered only once.

document.getElementById('audio_'+id).addEventListener("ended", function(){
        console.log("ended");
    });
}

$('.button').off().on('click', function(event){
event.stopPropagation();
event.bubbles = false;
var id = $(this).attr('id')
if ($(this).hasClass('hasAudio')) {
    document.getElementById('audio_'+id).play();
});