MikeyB
MikeyB

Reputation: 490

eventListener firing multiple times and increasing

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");
        });
    }
});

Upvotes: 7

Views: 12736

Answers (5)

madalinivascu
madalinivascu

Reputation: 32364

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");
 });

Upvotes: 2

Nandu Kalidindi
Nandu Kalidindi

Reputation: 6280

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="">

Upvotes: 1

Amal
Amal

Reputation: 278

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();
});

Upvotes: 0

Niel_patel
Niel_patel

Reputation: 74

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

Upvotes: 0

Rob Anthony
Rob Anthony

Reputation: 1813

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.

Upvotes: 0

Related Questions