eventListener firing multiple times and increasing - javascript

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

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

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

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.

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

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

Related

keypress handler canceling the event

I have the following code
jQuery('#parent').on('keypress', '.textbox', function(e) {
var btn = jQuery(this).closest('tr').find('.btn');
if (btn.length) {
btn.triggerHandler('click');
}
});
This code is a delegated keypress handler which is listening to the event of textboxes having class value ".textbox".
The handler finds the button with class ".btn" & calls its click handler which has an ajax call in it.
Problem is this seems to prevent the event from completing i.e if the value in box is "2" & I type in a "3",the handler executes but the value in the box remains to be "2" instead of a "23".
It works normal when I comment out the btn triggerHandler statement.
Ideas why this is happening?
Use keyup instead of keypress. As in your script you have triggered another event.
jQuery('#parent').on('keyup', '.textbox', function(e) {
var btn = jQuery(this).closest('tr').find('.btn');
if (btn.length) {
btn.triggerHandler('click');
}
});
keypress gets interrupted by triggerHandler and hence doesn't allow the default action of key press to occur. While keyup will perform default action first, then listen to handler.
I think you need to keyup function.
$(document).ready(function(){
$("input").keyup(function(){
var rs= $(this).val();
alert(rs);
$("input").css("background-color", "pink");
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
Enter your value: <input type="text">
Try to use 'onchange' insted of 'keypress' or 'keyup'
$(document).ready(function(){
$("input").onchange(function(){
var rs= $(this).val();
alert(rs);
$("input").css("background-color", "pink");
});
});

Issue with binding and unbinding a click listener in Angular JS

I'm trying to add a click listener to the document when a dropdown is open, so that when you click anywhere else in the document it closes the dropdown and unbinds the click listener. I'm using some code from https://stackoverflow.com/a/17342418
I've discovered an issue though.
Binding:
$(document).bind('click', $scope.remindersDropdownHandler(event));
Handler:
$scope.remindersDropdownHandler = function(event) {
var element = $("#remindersDropdown");
var isClickedElementChildOfPopup = element
.find(event.target)
.length > 0;
var buttonElement = $("#remindersButton");
var isbuttonElement = buttonElement
.find(event.target)
.length > 0;
if (isClickedElementChildOfPopup || isbuttonElement) {
return;
}
$scope.openReminders = false;
// $(document).unbind('click', $scope.remindersDropdownHandler);
}
The handler itself is working just fine, however it only ever executes once! And that's immediately when you click the button that opens the drop-down and adds the bind. After that no matter where you click it never fires the listener again. (Trust me I've done a lot of debugging with console.log() over the past hour.)
However, if instead of referencing a function for the handler, I instead write it like such:
$(document).bind('click', function() {
var element = $("#remindersDropdown");
var isClickedElementChildOfPopup = element
.find(event.target)
.length > 0;
var buttonElement = $("#remindersButton");
var isbuttonElement = buttonElement
.find(event.target)
.length > 0;
if (isClickedElementChildOfPopup || isbuttonElement) {
return;
}
$scope.openReminders = false;
});
That works, and each time I click somewhere on the document it correctly executes the handler and closes the drop-down. The problem is because I haven't referenced the handler via a variable, I can't unbind it, so the handler is permanently attached. I need to be able to unbind it so that my site doesn't get overloaded with click listeners on the document.
So my issues are:
1) When I reference $scope.remindersDropdownHandler() as the handler for my click listener, why does it only fire once and then never again?
2) How can I fix up my code so that I bind the appropriate function for the click listener, and then unbind it when I choose to do so?
Note: In the example code I'd commented out the // $(document).unbind('click', $scope.remindersDropdownHandler); just to reinforce that there was no code that was immediately unbinding my click listener.
Solved: A user on Reddit pointed out that removing (event) from the specified handler in the bind would allow it to work.
https://www.reddit.com/r/angularjs/comments/3fypck/help_issue_with_binding_and_unbinding_a_click/cttr0bw
I.e. converting
$(document).bind('click', $scope.remindersDropdownHandler(event));
to
$(document).bind('click', $scope.remindersDropdownHandler);

Separate click event from focus event in Angular.js

I want to add a click handler to an ng-focus callback, to start listening to all future click events. But when focus is initiated by a click, the click handler fires immediately as well. I can solve the problem with a $timeout, but this is a hack and it goes against everything I stand for. What have I become?!
My HTML:
<input type="text" name="q" ng-focus="inputFocus($event)" />
This .js works (this is inside a directive's link function):
scope.inputFocus = function (e) {
scope.displayHistory = true;
$timeout(function () {
$document.on('click', hideHistory);
}, 200)
};
function hideHistory() {
scope.displayHistory = false;
scope.$digest();
$document.off('click')
};
I want the following to work, but the problem is that the click callback fires immediately. As you might expect, if I tab to this field, the click callback does not get called. But if the focus event is triggered by a click, hideHistory gets called.
scope.inputFocus = function (e) {
scope.displayHistory = true;
$document.on('click', hideHistory);
};
I tried calling e.stopPropagation() and e.stopImmediatePropagation() but these solutions were not effective either.
Have you tried e.preventDefault(); ?
Anyway you can provide a fiddle to illustrate exactly what's going on?

How to stop an event if not triggered directly?

Lets say there is a textbox and a button. On the click of button a function is executed, and on the focusout of textbox, the button is clicked. What I wanna know is, is there a way, I can determine that weather the user clicked the button, or it was triggered by focusout event of textbox, so that I may do some custom work in the click event, if it was triggered by focusout of textbox?
I could write some code, but I don't even have any idea where to begin with, I know the jQuery event and event.which property, but I wonder if it/they could be useful in this situation?
you can use event.target to determine which DOM element has initiated the event, then you can check if this is the button or the textbox.
check this out for more information: http://api.jquery.com/event.target/
from the documetation:
event.target
The target property can be the element that registered for the event
or a descendant of it. It is often useful to compare event.target to
this in order to determine if the event is being handled due to event
bubbling. This property is very useful in event delegation, when
events bubble.
This depends on how you're triggering the function from the textarea blur event, if you're simply triggering the click event using the following approach:
$('#btn').click(
function(e){
buttonActivation(e);
});
$('#txt').blur(
function(e){
$('#btn').click();
});
Then I'd suggest evaluating the originalEvent object to see what the original event was (if there was no originalEvent then the function was called by a programmatic click event, with jQuery; whereas if the originalEvent.type evaluates to click then the button must have been clicked.
function buttonActivation(e) {
if (!e) {
return false;
}
else {
var oEvent = e.originalEvent;
if (oEvent === undefined) {
console.log('Programmatic event');
}
else if (oEvent.type == 'click') {
console.log('User-initiated event');
}
}
}
JS Fiddle demo.
If, however, you're using something like the following (simply calling the same function from a different place):
$('#btn').click(
function(e){
buttonActivation(e);
});
$('#txt').blur(
function(e){
buttonActivation(e);
});
Then I'd recommend either directly assessing e.target or e.type:
function buttonActivation(e) {
if (!e) {
return false;
}
else {
var oEvent = e.type;
if (oEvent === 'blur') {
console.log('Programmatically-triggered event, on ' + oEvent);
}
else if (oEvent == 'click') {
console.log('User-initiated ' + oEvent + ' event');
}
}
}
JS Fiddle demo.
You can use the event.target. By default, jquery provides the event to the handler function.
Here's an example : jsfiddle
You can pass an additional parameters when triggering the event and check them in event handler.
So if you wrote
button$.trigger('click', 'hello');
then you can write the handler like
button$.on('click', function(e, someStr) {
console.log(someStr || 'Nothing passed');
// Obviously if someStr is undefined, the user clicked the button,
// otherwise the $.trigger() method has been called.
});

Change event precedence with JQuery

I have the following html code:
<input type="text" id="theInput" value=""/>
Click me
I want to detect when the input changes and perform an operation in this case, but ONLY when the user has not clicked in the link. I have tried this:
$('#theLink').live('click', function(){
alert('click');
});
$('#theInput').live('change', function(){
alert('change');
});
However change is always executed before click when the value in the input changed, due to Javascript event precedence rules, and therefore only "change" message is displayed.
I would like it to display change only if the input value changed and the user exited the input clicking in any other place instead of the link. In that last case I would like to display click.
The example is here.
I use jQuery 1.6.4.
As far as I know, the click event fires after the blur and change events in every browser (have a look at this JSFiddle). The order of blur and change is different across browsers (source: Nicholas Zakas).
To solve your problem, you could listen to click events on the document and compare the event's target with #theLink. Any click event will bubble up to the document (unless it is prevented).
Try this:
var lastValue = '';
$(document).click(function(event) {
var newValue = $('#theInput').val();
if ($(event.target).is('#theLink')) {
// The link was clicked
} else if (newValue !== lastValue) {
// Something else was clicked & input has changed
} else {
// Something else was clicked but input didn't change
}
lastValue = newValue;
});
JSFiddle: http://jsfiddle.net/PPvG/TTwEG/
Both events will fire but in your example the alert in the onchange event handler fired when the onmousedown event occurs will stop the onmouseup event required for the onclick event to fire. Using console.log will show both events firing.
http://jsfiddle.net/hTqNr/4/
Ok, now i got it, you could do
$('#theLink').live('click', function(e){
alert('click');
});
$('#theInput').live('change', function(e){
//Check if the change events is triggerede by the link
if(e.originalEvent.explicitOriginalTarget.data === "Click me"){
//if this is the case trigger the click event of the link
$('#theLink').trigger("click");
}else{
//otherwise do what you would do in the change handler
alert('change');
}
});
Fiddle here http://jsfiddle.net/hTqNr/19/
why you dont pick the value of input box. you have to store initial value of input box on ready function
initialvalue= $('#theInput').val();
then compare the value
$('#theLink').live('click', function(){
var newvalue =$('#theInput').val();
if(newvalue!=initialvalue) {
//do something
}
});

Categories