jQuery - click-event is called twice on iPad - javascript

I have a problem with my web application which is designed for iPad.
I use jQuery and jQuery UI for dragging elements on the screen. Because on iPad, the element can not be dragged by default, I added this library:
http://code.google.com/p/jquery-ui-for-ipad-and-iphone/
Including it, I can drag and drop elements on iPad, but also a problem occurs. I have on the draggable element also a div are with an image, which should be clickable.
So I integrate these lines:
$(document).ready(function() {
$(".note").draggable();
$('.closebutton').click(function() {
alert("test");
});
});
​
The problem is, including the drag-library, the alert message test pops up twice or the screen is frozen.
I created a full working demo here:
http://jsbin.com/oliwo/2/
On normal desktop browsers, like Firefox 4 Beta and Safari, it works, only one test message appears by clicking with the mouse on the x - delete image. On iPad, I get the message twice or the screen froze.
Does anyone can help me? Thank you a lot in advance & Best Regards.

This is not really a response, as i don't known why you have it twice. But you can try a workaround if you're sure your click event is the only click event behavior that should be attached to this button; Make an unbind() just before you're bind, this will remove any previous click binding (so if this is run several times, you'll get only one event):
$('.closebutton').unbind().click(function() { ...
or better:
$('.closebutton').unbind('click').click(function() { ...

I've found that events get fired twice when showing an alert box on a click. I've managed to overcome this problem by using a setTimeout to show the alert box...
$("#myButton").unbind("click").click(function () {
// Have to use a setTimeout else on iPhone the alert may appear twice in certain scenarios
setTimeout(function () { alert('The message'); }, 300);
return false; // Return false to prevent href being followed
});

I do not know why, but if I do not use alert messages, it will work. I create new elements and then it is only called once, on iPad and Desktop Safari.

I'm seeing this issue only on iPad, perhaps some version of webkit related. The unbind worked for me, and I also read this only exists if jquery code is in the body html tag, if its in head it is not an issue.

just simply avoid the propagation of the click
$("tr").live('click',function() {
...
$( event.toElement ).one('click', function(e){ e.stopImmediatePropagation(); } );
});

Related

How to unbind() .hover() but not .click()?

I'm creating a site using Bootstrap 3, and also using a script that makes the dropdown-menu appear on hover using the .hover() function. I'm trying to prevent this on small devices by using enquire.js. I'm trying to unbind the .hover() event on the element using this code:
$('.dropdown').unbind('mouseenter mouseleave');
This unbinds the .hover of that script but apparently it also removes the .click() event(or whatever bootstrap uses), and now when I hover or click on the element, nothing happens.
So I just want to how I can remove the .hover() on that element, that is originating from that script, but not change anything else.
Would really appreciate any help.
Thanks!
Edit: Here is how I'm calling the handlers for the hover functions:
$('.dropdown').hover(handlerIn, handlerOut);
function handlerIn(){
// mouseenter code
}
function hideMenu() {
// mouseleave code
}
I'm trying to unbind them with this code.
$('.dropdown').unbind('mouseenter', showMenu);
$('.dropdown').unbind('mouseleave', hideMenu);
But its not working.
Please help!
**Edit2: ** Based on the answer of Tieson T.:
function dropdownOnHover(){
if (window.matchMedia("(min-width: 800px)").matches) {
/* the view port is at least 800 pixels wide */
$('.dropdown').hover(handlerIn, handlerOut);
function handlerIn(){
// mouseenter code
}
function hideMenu() {
// mouseleave code
}
}
}
$(window).load(function() {
dropdownOnHover();
});
$(window).resize(function() {
dropdownOnHover();
});
The code that Tieson T. provided worked the best; however, when I resize the window, until I reach the breakpoint from any direction, the effect doesn't change. That is, if the window is loaded above 800px, the hover effect will be there, but if I make the window smaller it still remains. I tried to invoke the functions with window.load and window.resize but it is still the same.
Edit 3: I'm actually trying to create Bootstrap dropdown on hover instead of click. Here is the updated jsFiddle: http://jsfiddle.net/CR2Lw/2/
Please note: In the jsFiddle example, I could use css :hover property and set the dropdow-menu to display:block. But because the way I need to style the dropdown, there needs to be some space between the link and the dropdown (it is a must), and so I have to find a javascript solution. or a very tricky css solution, in which the there is abot 50px space between the link and the dropdown, when when the user has hovered over the link and the dropdown has appeared, the dropdown shouldn't disappear when the user tries to reach it. Hope it makes sense and thanks.
Edit 4 - First possible solution: http://jsfiddle.net/g9JJk/6/
Might be easier to selectively apply the hover, rather than try to remove it later. You can use window.matchMedia and only apply your script if the browser has a screen size that implies a desktop browser (or a largish tablet):
if (window.matchMedia("(min-width: 800px)").matches) {
/* the view port is at least 800 pixels wide */
$('.dropdown').on({
mouseenter: function () {
//stuff to do on mouse enter
},
mouseleave: function () {
//stuff to do on mouse leave
}
});
}
else{
$('.dropdown').off('mouseenter, mouseleave');
}
Since it's not 100% supported, you'd want to add a polyfill for those browsers without native support: https://github.com/paulirish/matchMedia.js/
If you're using Moderizr, that polyfill is included in that library already, so you're good-to-go.
I still don't understand how you intend to "dismiss" the dropdown-menu once it is displayed upon mousing over the dropdown element partly because there's not enough code in your question, but that's sort of irrelevant to this answer.
I think a much easier way to approach the mousenter event handling portion is not by using off()/on() to unbind/bind events at a specific breakpoints, but rather to do just do a simple check when the event is triggered. In other words, something like this:
$('.dropdown').on('mouseenter', function() {
if($('.navbar-toggle').css('display') == 'none') {
$(this).children('.dropdown-menu').show();
};
});
$('.dropdown-menu').on('click', function() {
$(this).hide();
});
Here's a working fiddle: http://jsfiddle.net/jme11/g9JJk/
Basically, in the mouseenter event I'm checking if the menu toggle is displayed, but you can check window.width() at that point instead if you prefer. In my mind, the toggle element's display value is easier to follow and it also ensures that if you change your media query breakpoints for the "collapsed" menu, the code will remain in sync without having to update the hardcoded values (e.g. 768px).
The on click to dismiss the menu doesn't need a check, as it has no detrimental effects that I can see when triggered on the "collapsed" menu dropdown.
I still don't like this from a UX perspective. I would much rather have to click to open a menu than click to close a menu that's being opened on a hover event, but maybe you have some magic plan for some other way of triggering the hide method. Maybe you are planning to register a mousemove event that checks if the mouse is anywhere within the bounds of the .dropdown + 50px + .dropdown-menu or something like that... I would really like to know how you intend to do this (curiosity is sort of killing me). Maybe you can update your code to show the final result.
EDIT: Thanks for posting your solution!

Is jQuery 1.3.2 causing this not to work, or something else?

I know that this is supposed to work, it works fine in 1.7.2
//click anywhere to close dropdown
$("html").live("click", function () {
closeDropdown();
});
//on click of ellipsis, open dropdown
$("span.PivotEllipsis").click(function (e) {
e.stopPropagation();
openDropdown();
});
It is the classic click outside span.PivotEllipsis to hide. However, the problem is that the second function is not working. The first is working fine, when you click outside, it hides. However, when you click on the span.Pivot Ellipsis it doesn't pop up, instead I think, hard to tell though, that it runs openDropdown() and then immediately after closeDropdown()....
Anyone know what it wrong?
According to jQuery Documentation: "it is not possible to stop propagation of live events." You don't really need to use .live() as the html element exists at document.ready and isn't dynamically loaded
What you thought is probably correct - you need to disable the first function while the dropdown menu is not open.

Google chrome, infinite loops and selecting text

This question comes with a bit of background. Please see two other questions I've recently posted that relate:
How to select text in a textbox cross-browser
Infinite loops created in google chrome
Word of warning: it's possible that the second link is a red herring.
Ok so my problem is that I'm trying to have it so when a user first clicks or tabs in to a textbox, all the text should become selected. If the textbox has focus, subsequent clicks on the text inside the textbox should behave normally (ie. doesn't re-select all the text). The answer I choose in the first link above is the one I found worked across all browsers. Code posted below for your convenience:
$('input[type="text"]').live('focus', function (event) {
var inp = this;
setTimeout(function () {
inp.select();
}, 1);
event.stopPropagation();
event.preventDefault();
return false;
});
Now my second link above is what I seem to be running in to with this approach. It seems that intermittently, google chrome gets stuck somewhere and starts changing the focus between textboxes really fast. You can see what I think is happening here: http://jsfiddle.net/ajbeaven/XppG9/14/
Like I said, it seems to be an intermittent problem so you might have to try reloading the page a couple of times in order to see what I think might be causing the changing of focus. Remember, it only seems to happen in chrome.
Thanks to anyone who can shed some light!
Put any additional work in the setTimeout function. And add a clearTimeout() before you setTimeout():
var focusTimeout = 0;
$('input[type="text"]').live('focus', function(event) {
var inp = this;
clearTimeout(focusTimeout);
focusTimeout = setTimeout(function() {
$('#message-container').html($('#message-container').html() + "*\u200b");
inp.select();
}, 1);
});
http://jsfiddle.net/XppG9/19/
In Chrome, writing the html to the page is (apparantly) causing the field to lose focus, and select() is causing it to receive focus 1ms later, thus triggering the focus event and causing the infinite loop. Moving the write html call into the function that selects the text seems to do the trick.
Oh man, I just figured it out. This bug probably won't happen to you on a real website. It's happening because you are updating the DOM adding a "*" to the message div. When you do this, it pushes the content of the page down. This moves the top text box to where the mouse is, and the mouseup event is triggered on the top text box, causing both text boxes to fire a setTimeout and getting in an infinite loop. Total dibs on reporting this.
edit: it's probably not the mouseup event. looks like chrome thinks you are legit focusing on both. Here's the bug test case for Chrome: http://jsfiddle.net/delvarworld/AnBE8/
edit2: This happens in Safari too. Most likely a webkit issue.
tldr simple workaround is to not update the dom in a way that causes reflow on the focus event, as in get rid of the html() line
You could also try:
$('input[type="text"]').live('mouseup', function (event) {
Which works in Chrome for me

Mobile Safari Event Issue

I have designed a website with a menu that is initially invisible. When the user clicks on a button, the menu becomes visible. There are two ways for the user to hide the now visible menu:
Click the button that caused the menu to become visible
Click anywhere on the web page that isn't the menu
The way I have coded the second option is to tie an onclick event to the window element, and have it compare where the user clicked to the menu's position to determine if the menu should be hidden. This works great in Firefox and Safari, but it fails in Mobile Safari.
I noticed that the window onclick event only fires when I click on another element with an onclick event already assigned. If I click on an element with no event(s) assigned, the window's onclick event never fires. If I click on the button which displays the menu, it fires along with the event tied to the button.
Is it possible to assign events to the window element in Mobile Safari?
I'v been encountering this same problem. Here is what worked for me. (Note: I am working within a Modernizr and jQuery context)
First, I add a custom Modernizr class using Modernizr's addTest Plugin API to test for iOS, which will add the class appleios or no-appleios accordingly.
Because in my research the body seems to fire events on it's own agenda, I am taking a little precaution by wrapping all the document's content with an element in an iOS context. Then I add an event handler to this element.
$(".appleios body").wrapInner('<div id="appleios-helper" />');
$("#appleios-helper").bind("mouseup", function(){return;});
What was suggested earlier in this thread is using void(0). I did some quick testing, and found that void(0) as the event just wasn't causing touches on the body to be recognized. When I plugged in my own "empty" function in the form of function(){return;} things started working.
This all hinges on the fact that no events are fired in Mobile Safari unless the element explicitly has events to fire (Safari Web Content Guide.) By inserting this empty event on the wrapper, things will bubble up to the body.
If you're doing strait JavaScript with none of these libraries, the same effect could be achieved in the HTML markup
<html>
...
<body>
<div id="appleios-helper" onmouseup="function(){return;}">
...
</div>
</body>
</html>
This worked for me to hide tooltips when touching anywhere on the document's body. Your mileage may vary.
Simply adding the dummy onclick handler to the html body works for me:
<body onclick="void(0)">
Note that I am using usual live event handlers as shown below:
function liveHandler( event ) {
var target = event.target; ...}
window.addEventListener(evtype, liveHandler, true);
// evtype such as 'mousedown' or 'click'
// we use the capturing mode here (third parameter true)
This is an old question, but I struggled with the same thing today.
I found that using touchstart event works.
I solved it like this:
var isTouchDevice = 'ontouchstart' in document.documentElement;
if (isTouchDevice) {
// Do touch related stuff
$(document).on('touchstart', function (event) {
// Do stuff
});
} else {
// Do non-touch related stuff
$(document).on('click', function () {
// Do stuff
});
}
You could just add onclick="void(0);" to some <div> that covers the whole page so that no matter what, you are always clicking on an element that has an onclick event. Not a great solution, though.
I'd prefer not having the onclick event be tied to the window. Why don't you create a container <div> that has that event on it. Then handle it just like you currently are.
You can also:
$('body').css('cursor', 'pointer');
No idea what those "engineers" at Apple are doing. LOL.
This has problems though. You wouldn't want to do this on every touch device. Only touch devices that don't also have a pointing device (Laptops with Touch Screens, for example).
Source: http://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
The conclusion of the article is this:
So I don’t understand why all this is the case, but it most certainly is the case. If you’re having bubbling problems, just add an empty-function event handler anywhere between the body and the element, and you’re set to go. But it shouldn’t be necessary.

Javascript detect when drop down list is closed

Because of the issue explained in this question I have a situation where I need to attach the mousewheel event to the drop down list only when it is expanded (I do this in the onclick event). However I need to remove the mousewheel event when the list collapses. How do I go about detecting this?
I can't just use the onchange event because the user may not have actually changed their selection. I've tried the onblur event but in most browsers (except IE) the drop list stays focused when the list is collapsed.
Cheers.
var list = document.getElementById("list");
list.onclick = function (e) {
// attach mousewheel
list.onmousewheel = function (e) {
// ...
}
// attach click off
// This event fires fine in all browsers except FF when the list is expanded.
// In firefox it only fires when anywhere in the document is clicked twice.
// The first click closes the drop down list as expected and the second one
// fires the event.
window.document.onclick = function (e) {
list.onmousewheel = null;
window.document.onclick = null
}
};
EDIT:
Unfortunately meder's solution doesnt work in firefox. The click event on the document doesn't get fired until i click twice off the drop down list. How do I get around that? It works fine in IE.
EDIT2:
I've done some more testing and the following browsers behave as expected
IE 7,
Chrome 3
Opera 10
Firefox requires 2 clicks in the window to make it work & Safari doesn't work at all.
It appears that even when you click off the drop down list firefox maintains focus on it. It's not until the second click occurs that the drop down list eventually loses it's focus.
Are you looking for something like this? If the user clicks anywhere that's not within #el, it will branch out and you can do what you want, though this requires jQuery but it would take far too many lines of DOM Scripting.
var dropdown = $('#el');
$(document).click(function(e){
if ( (!$(e.target).is(dropdown)) || !$(e.target).closest('#el').length ) {
// do what you need to
}
});
If not, can you be more specific and include an example?
PS - I did not test the snippet, sorry if it isn't what you want.
OK, I still have no idea what you're trying to achieve with such a tightly-scripted select box, but in general trying to change the internal working of a native <select> isn't fruitful. There's no standard that says how events flow internally to the form element, and browsers that implement select as an OS-level widget (IE) can't do much to support it anyway.
If you must have this behaviour, I'd suggest using scripting to replace the <select> box on-fly with a JavaScript-powered analogue made out of <div>s. Then you can control exactly how each mouse and keyboard interaction behaves. There are many libraries that do this already, though again if you need to be very specific about the exact behaviour they might not suit you.

Categories

Resources