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.
Related
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...
I use jQuery 1.6.2. I want to call a click event just for once when that element appears at page. This is my selector:
span[resizer='north'][title=''] :first-child"
This can work for triggering click event:
$("span[resizer='north'][title=''] :first-child").click();
How can I make it work only once or after that element appears on the page?
Answer as per how I understand your last comment: I mean I will call click event only once. Let's assume that there is a button. I will call click event of that button once. I mean I will programmatically click that button.
$('button').click(function() {
$('span[resizer='north'][title='']:first-child').click();
$(this).unbind('click');
});
You may use DOMNodeInserted event to detect when new element is inserted dynamically.
var alreadyclicked = false; // variable to check that it will be clicked just once
$(document).bind('DOMNodeInserted', function(e) {
if (!alreadyclicked){
$("span[resizer='north'][title=''] :first-child").click();
alreadyclicked = true;
}
});
Update
The DOMNodeInserted event is deprecated along with other mutation events. Some browsers support it, but looks like this won't last long.
You can use mutation observers instead to keep track of changes in DOM
var alreadyclicked = false;
var observer = new MutationObserver(function(mutations, observer){
//if new nodes were added
if( mutations[0].addedNodes.length && !alreadyclicked )
$("span[resizer='north'][title=''] :first-child").click();
alreadyclicked = true;
});
observer.observe( document, { childList:true, subtree:true });
Use a custom event, with a delegated handler attached using .one().
An event has 2 components, triggering and handling. Don't focus on how many times it's triggered, focus on how many times it's handled.
$("document").one("myclick", "span[resizer='north'][title=''] :first-child", function(e) {
do something...;
$(this).click(); //if you actually need the "click"
});
$("span[resizer='north'][title=''] :first-child").trigger("myclick");
This example will mean it's "handled" one time. The other answers on here can be used to ensure it's triggered when the element is added if it's after document ready.
You could also use a pub/sub which would make it even easier. Then you just have to trigger your custom event from the ajax or whatever code that would add the element and not worry about specifically targeting the element. Last line of code in the subscription would be to unsubscribe.
I have a simple div with a link with in:
<div class="mhButton">
<span class="icon-checkmark"></span> Register Animal
</div>
I've have a function that is triggered whenever the 'div.mhButton' is clicked. This function should find 'div.mhButton' child 'a' and click it.
$(".mhButton").on('click', function () {
var a = $(this).find("a").text();
console.log(a);
$(this).find("a").click();
});
This works, however, I get stuck in a loop that runs like 639 times.
I can't comprehend why this runs X amount of times, then continues without error.
Does anyone have a solution on how to prevent this? Along with an explanation on why this happens?
Note* The console is logging the same button, again and again.
Because the a tag is embedded in the button, you are continuously re-firing the event. Events will bubble up, so the anchor will get clicked, and then its parent. It is running until the browser gets tired of running it and then it just stops. The method doesn't actually do anything which is likely why you aren't seeing any issues. You can accomplish your goal a couple of ways:
$(".mhButton").click(function () {
$(this).off('click'); // turn the click handler off in the handler itself.
var a = $(this).find("a").text();
console.log(a);
$(this).find("a").click();
});
If you do this, then you will end up only being able to fire the event once.
Alternatively:
$(".mhButton").click(function (e) {
a = $(this).find("a").text();
console.log(a);
$(this).find("a").click();
});
$("#RegisterAnimal").click(function (e) {
e.stopPropagation(); // prevent the anchor from re-firing the button click
});
Altenatively, you can just style the link to look like a button and avoid the unnecessary click handlers all together.
When you call $(this).find("a").click(); the event will bubble up to the div.mhButton tag and cause your handler to be called again. The reason it runs around 500 times is because it stops with a stack overflow, it does not continue
You can prevent it by checking if the click was the <a> tag itself and not calling click() in that case
Working example: http://jsfiddle.net/mendesjuan/zdkrhh42/
Note Regarding the accepted answer
Bic's second answer almost works, mine is a different approach with fewer side effects. The main problem with calling stopPropagation is that there may be handlers on the whole document that wouldn't get fired in that case. A commmon case is when you have a menu or a dialog that is supposed to hide when you click anywhere else on the page. The stopPropagation approach will prevent the menu from being hidden when they click your button.
$(".mhButton").click(function (e) {
// Only run this handler if the click was on the div, not the link itself
if ( $(e.target).is('a, a *') ) {
return;
}
var a = $(this).find("a").text();
$(this).find("a").click();
});
I have 2 DIVs and in each DIV there's a Button which does something on click.
Now I've added a piece of code to bring the DIVs to front when they get a mousedown. Which works very well. The problem is, that they swallow the mousedown of the inner button... The inner button can only be clicked by double clicking it.
http://jsfiddle.net/nUtz6/
$('div').mousedown(function (event) {
$(this).parent().append($(this));
});
how could I solve this problem? I did it this way because I don't want to increment the z-index of the CSS property to some magic number everytime I click the div. I read that jquery also does the DOM manipulation trick.
The problem seems to occur because I change the DOM right before the click-Event of the button. If I don't do anything in the mousedown, everything works fine.
Just check that the DIV is actually the target of the event :
$('div').mousedown(function (event) {
if (event.target.tagName.toLowerCase() != 'button')
$(this).parent().append($(this));
});
FIDDLE
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