Delegated event triggering even when it shouldn't - javascript

I have the following code:
// Define controls
$('.play-video').click(function(){
// Get the video element
var video = $(this).parent().parent().find('video');
// Play the video
$(video).get(0).play()
// Remove the play class and add the pause class so the same button will pause the video
$(this).removeClass('play-video');
$(this).addClass('pause-video');
// Set pause text
$(this).text('Pause');
});
$(document).on('click','.pause-video',function(){
console.log('pausing...');
// Get the video element
var video = $(this).parent().parent().find('video');
// Play the video
$(video).get(0).pause()
// Remove the play class and add the pause class so the same button will pause the video
$(this).removeClass('pause-video');
$(this).addClass('play-video');
// Set pause text
$(this).text('Play');
});
Problem is, that the second click event should trigger on .pause-video only but also triggers on .play-video
Question is: What did I do wrong?
Thanks in advance,
G3

You've attached the "play" event handler directly to the button instead of using delegation. That handler will continue to fire because of that, even if you change the class.
Delegation works through event bubbling, and the selector you pass in to the .on() call is re-examined with every event. That is not the case with handlers that are directly attached: once those are active, they're active until they're removed or until the DOM element itself is removed. Changing the particulars of the DOM element won't make a difference.
Your problem can therefore be solved by using delegation for both cases.

Your code is close. but your first event handler also needs to be delegated too:
$(document).on('click', '.play-video', click(function(){

try to stop immediage propagation $('.play-video').click

The problem is that jQuery can't track object changes on the fly. Just use one click event, and determine what to do inside this:
$('.play-stop-video').click(function(){
if($(this).hasClass('play')) {
// Current play button code here....
}
if($(this).hasClass('stop')) {
// Current stop button code here....
}
$(this).toggleClass('play').toggleClass('stop');
});
$(something).click( ... will runs when the page loads, and attach the click events to the play and stop buttons. However, you don't have any stop buttons at this time, so the click event for this will be discarded...

Related

Remove touchpointer in javascript

I was trying to make a webapp with html elements that will move form div to antoher div when clicked but also I want to be able fire event when users hold that element for more than a second. So I have this code
$(document).on("click",'.card', function() {
var card=$(this).parent();
if(card.parent().attr('id')==="options"){
card.appendTo("#choice");
}
else{
card.appendTo("#options");
}
});
var timeoutId = 0;
$('.card').on('pointerdown', function() {
timeoutId = setTimeout(showModal, 1000);
}).on('pointerup mouseleave', function() {
clearTimeout(timeoutId);
});
And it is doing almost fine. The problem occures when the element is clicked. It is appended to different div as it should but the mobile pointer is still on it so when I try to fire 'hold' event on another element it is not working for the first time since 'pointerup' event from previous element is firing right after 'pointerdown' event (So you need to try to hold next element twice).
I've dealt with it by adding a simple boolean flag in click event function so it is blocking next first call of 'pointerup' event but this is a very ugly solution.
Do you have any ideas how can i improve this? Maybe there is a way to call 'pointerup' event manually after click?
Removing 'mouseleave' event and adding 'pointerleave' instead fixed the problem.
Not really sure how 'mouseleave' event was fired on mobile device though.

Removing a listener class doesn't stop a sound event associated Jquery Javascript

I'm playing a sound when hovering on an image (this is working fine already) and want to include a button to turn this off if desired. Unfortunately I haven't been able to make it work.
My current code goes like:
For creating the sound
//a bunch of code to generate the audio that ends on
var mouseoversound = createsoundbite('mysound.mp3')
For triggering it
$(".play").mouseover(function() {
mouseoversound.play();
});
The listener element
<%= image_tag "image.png", class:'logo-image play' %>
I thought that the simplest solution for disabling it was to remove the class 'listening' for the event (i.e. '.play') in the element listener, so I tired:
$(".sound").click(function(){
$(".logo-image").removeClass("play");
});
//.sound is the class of the button that's intended to block it.
Although the latter script does successfully remove the class 'play' the sound keeps playing every time I hover over the image. What am I missing? shouldn't the sound just stop playing?
Do you see any other solution to this?
Cheers
The issue is because the event handler is bound to the element. Removing the class after the event is bound does not affect that binding. To affect the event handler, you can call off(), like this:
$(".sound").click(function(){
$(".logo-image").off('mouseover');
});
Alternatively, if you want to toggle the sound functionality based on the class, you can keep your current logic and check that the element still has the class in the mouseover handler:
$(".logo-image").mouseover(function() {
if ($(this).hasClass('play') {
mouseoversound.play();
}
});
$(".sound").click(function(){
$(".logo-image").toggleClass("play");
});

GetElementby More Item

I use the VideoJS framework, i want know when the user pause the video. The video go to pause when i click on "Play button" and on video:
var vjs = document.getElementById("really-cool-video_html5_api"); // on video
var vjs = document.getElementById("really-cool-video").getElementsByClassName("vjs-play-control")[0]; // click button play
I with Listener, see if the user click on this "div" :
vjs.addEventListener("click", checkPause, false);
but it control only when i click on document.getElementById("really-cool-video").getElementsByClassName("vjs-play-control")[0] i want, both 2 div in my listener... I can't change the HTML and tell the div with the same name... How i can do a Listener of two elements?
You're probably better off using video.js's api to listen for pause events instead. There are ways to pause the video without clicking (keyboard control) and clicks that do not pause the video (play).
videojs('really-cool-video').on('pause', checkPause)
You have the same named variables your attaching listeners to. Try changing the second vjs to vjsBtn like so...
var vjsInnerBtn = document.getElementById("really-cool-video_html5_api"); // on video
var vjsPlayerBtn = document.getElementById("really-cool-video").getElementsByClassName("vjs-play-control")[0]; // click button play
Now you are free to accomplish this.
vjsInnerBtn.addEventListener("click", checkPause, false);
vjsPlayerBtn.addEventListener("click", checkPause, false);
I'm assuming jQuery is available to you, since you've tagged it. This makes things much easier for you, because you simply have to fill the selector with the elements you want the event handler attached to:
$('#really-cool-video_html5_api, #really-cool-video .vjs-play-control').on('click', checkPause);
Note, this still adds multiple event handlers, this must be done if you want the same functionality triggered from a click on two different elements.
have you considers store them in an array? like
var controls['video'] = document.getElementById("really-cool-video_html5_api"); // on video
controls['pause_btn'] = document.getElementById("really-cool-video").getElementsByClassName("vjs-play-control")[0];
//Here you add the addEvenListener with the array elements.
is the same approach to using different variables but you can iterate them if you want to attach them same event listener or use a function for that

JavaScript Click event fires via the Enter Key but not via the Mouse

Some code that looks like the following is firing the click event via the Enter key, but is not responding to the mouse click.
//a is an anchor element
a.addEventListener('click', function (e)
{
//Do Stuff...
});
This page demonstrates the problem. The relevant bit of code is at line 176. This is in the middle of development and currently only (sort of) works in Chrome.
Also, I just verified that it works if I use mousedown, so it's not just the case of an invisible element sitting in front of the anchor.
Any ideas?
Edit: Now that you've shown us the actual code you're using, the problem is related to the fact that the autoSuggest() function has it's own click handler and in that click handler, it is clearing the container which removes all <a> elements in the container so your link object gets destroyed (probably before your click event gets to process). So, you can get events that happen before the click (like mousedown), but after a click, the element is removed from the DOM.
If you tell us what you're trying to actually do when an auto-suggest item is clicked that is different than the default behavior of the autoSuggest() function and you point to any documentation for that function, then perhaps we could offer a better way to solve your issue.
The link may be firing and taking you off to a new page (or reloading the current page), thus preventing you from seeing the click code run. Usually when you process a click event on a link element, you need to prevent the default behavior:
//a is an anchor element
a.addEventListener('click', function (e) {
e.preventDefault();
//Do Stuff...
});
Another possibility is that you are trying to install the event handler too soon either before the DOM has been loaded or before this particular link has been created and thus no actual click event handler is attached to the DOM object. You can verify whether the event handler is even getting called by temporarily putting an alert("Click handler called"); in the event handler and see if that pops up or not.

Can mouseenter and click event exist together?

I am wondering if mouseenter and click event can exist together and they can both exist to TRUE when checked with:
if ((evt.type === 'mouseenter') && (evt.type === 'click'))
It is because when I mouse over the link, the mouseenter triggers (set to TRUE) and even when I clicked on it, the hover is still shown. Probably they could exist together but I'm no expert on this.
If someone can give insights, I would appreciate it a lot.
Also how can I trigger the click event during the mouseenter event?
The mouseenter event fires when the mouse enters the control. The click event fires when the mouse is clicked. They are two separate events which call two separate event handlers. If you click just as the mouse enters the element they will be called within a short timespan of one another but they are still two distinct events.
It is also important that you differentiate between the mouseenter and the mouseover events. mouseenter fires when the mouse physically enters an element, whereas mouseover fires continually while the mouse remains over an element.
While you cannot trigger the click event per se, you can call the same function that is called by the click event handler. For example if you have this:
var myfunc = function (e) { ... }
document.getElementById("id").onclick = myfunc;
Then you could simply call myfunc directly and you would get the same result as if the mouse was clicked.
They can 100% exist together, and this is a great question with no good answer... When you're on a mobile device, a mouseenter event will be thrown on tap... If you are also detecting onclick as well as mouseenter, then there will be a discrepancy between mobile devices and desktop machines.
It's kind of hard to solve such a small issue at the moment.
const x = document.getElementById('some_node')
x.onclick=(e)=>{
e.stopPropagation()
// this logic will be triggered on click for both desktop and mobile
}
x.onmouseenter=(e)=>{
e.stopPropagation()
// this logic will be triggered on click for mobile only (but will
//have already been triggered on desktop when cursor entered node)
}
The only workaround I came up for this, and I think it's pretty clever, is using a eventlistener for taps/touches. The order/priority that these events are fired goes: touch > mouseenter > click.
Since the touch event is fired first, you can add a touch event listener (which will only register on a mobile device), and change a variable that prevents the mouseenter event from being triggered (which is the logic that would generally be conflicting with the onclick logic)... like this:
let isMobile = false
x.addEventListener('touchstart',(e)=>{
isMobile = true
}, false);
Then your mouseenter would need to look like this:
x.onmouseenter=(e)=>{
e.stopPropagation()
if(!isMobile){
// this logic will no longer cause a conflict between desktop and mobile
}
}
they can exist on the same object, think a button with a hover state and then a click action. The click event, though will only read the click event since the enter event actually occurred earlier.
You can create a var like mouseIsOverand set it to true when the enter event fires. I can be safely assumed, though that if a click happens the mouse is over the same target.
The two events may happen at the same time, but they will still be processed on after the other. So the if you posted will never evaluate to true.
If you look at your code again you can see that it doesn't make sense. How can something be X and Y at the same time? It can't.
for the first question i think u got an answer....
however, for Also how can I trigger the click event during the mouseenter event?
u can use trigger() function..
http://jsfiddle.net/PDhBW/2/
if u want to read more about trigger
here is the link
http://api.jquery.com/trigger/
With Jquery event delegation, You can use binding multiple events at once
$('#IdElement').on('mouseenter click', function () {
//Your Code
});
http://jqfundamentals.com/chapter/events

Categories

Resources