I've been tasked to determine why when an IPAD user attempts to use any tab bar it doesn't register as clickable at all. You can jab your finger at the button all day long, but as far as the IPAD is concerned it is just text it seems. A little project background is that its developed in asp MVC and uses LESS. I tested Safari 6 on my computer and a mac, the tabs are fine in those environments. Conflicting reports on whether the problem exists on the iPhone.
I did get my hands on a mac and an IPAD2 for the next few weeks. I've got web inspector running.
<div id="Tabs" class="tabContainer" >
<ul>
<li id="UserAdmin" class="selected">Users</li>
<li id="CompanyAdmin">Companies</li>
<li id="AdminMessages">Admin Messages</li>
</ul>
</div>
<div class="tabContentDivider">
</div>
<div id="tabPlaceHolder" class="tabContent">
<% Html.RenderPartial("ManageUsersPartial", Model, new ViewDataDictionary()); %>
</div>
JS:
$(function () {
$('#Tabs ul li:not(.selected)').live('click', function () {
$('#tooltip').remove();
var selectedTab = $(this).attr('id');
$('#Tabs ul li').removeClass('selected');
$(this).addClass('selected');
$(window).unbind('resize');
loadRequest($('.tabContent'), global.baseUrl() + 'Admin/ShowTab/' + selectedTab, function () { });
});
});
function loadRequest($container, resource, onComplete) {
$.get(resource, function(result) {
$result = $(result);
if ($('#ExceptionPanel', $result).length > 0) {
$('body').html(result);
} else {
$container.html(result);
if (onComplete)
onComplete();
}
$result.remove();
});
}
What is missing here? Some CSS tag? I'd prefer not change the JavaScript. This is mature code.
In iOS, the click event fires only on <a> elements (and possibly some form inputs). You should add the handler for touchstart event:
$('#Tabs ul li:not(.selected)').live('click touchstart', function () {
//...
});
Still, the problem might be more complicated, since users will experience the handler behaviour even when they want to scroll the page and, for that purpose, tap the screen in the li area.
The ultimate solution would introduce touchstart as well as touchend and checking if $(window).scrollTop() or mouse (finger) position has changed. The code might look like this:
var scrollTop = false;
$('#Tabs ul').on('touchstart', 'li:not(.selected)', function (e) {
e.preventDefault(); // IMPORTANT - this line fixes the Android bug but be aware that it might unintentionally prevent from scrolling the document
scrollTop = $(window).scrollTop();
});
$('#Tabs ul').on('click touchend', 'li:not(.selected)', function () {
// let's give it a 10px threshold, since the `click` is not always a pure point `click`
// still, you might want to experiment with different thresholds
if (false !== scrollTop && 10 < Math.abs(scrollTop - $(window).scrollTop())) {
return scrollTop = false;
}
// ...rest of your code
});
EDIT:
I replaced e.pageY with $(window).scrollTop() - touch position might stay the same in relation to the document while scrolling the page.
EDIT 2:
You described the problem as related to the iOS but it would also show up on Android devices. There, you can add one more line to the touchstart handler: e.preventDefault(). I could mention that before but somehow I didn't. There is a known problem with touch events on Android, where sometimes the touchmove and touchend events refuse to fire. The added line of code resolves the problem.
Note that e.preventDefault() might prevent the document from scrolling. As I already mentioned, I have no possibility to test it.
EDIT 3:
According to Mike Barwick's comment, thanks #Mike for the edit. I also modified it a bit. The OP probably used .live method due to event delegation - I guess he adds <li> elements dynamically, so it would be better to pass .li:not(.selected) as the second argument of the .on method. More info HERE.
Related
I am having a hybrid app and whenever I click on any DOM input the keyboard comes and it takes my footer also along with at its top. But I need that the footer is stuck always at the bottom. What is the best way to do it ? Also am using the below jquery but it doesn't works flawlessly. Also in this jquery, I need to skip some input boxes whose classname not equals to item . How to add this exception ? Also is there any other nice way out to accomplish this task ?
if ('ontouchstart' in window) {
/* bind events */
$(document)
.on('focus', 'input[type=text]")', function() {
$('.footer').css('position', 'absolute');
$('.footer').css('bottom', '');
})
.on('blur', 'input[type=text]', function() {
$('.footer').css('position', 'fixed');
$('.footer').css('bottom', '0');
});
}
first of all i'm no js expert,and all my know how,is from web and mainly from here.
I code a js (jquery) which is based on aion MMORPG and shows tooltips related to the item-id or what else can be found ingame. I came across several hurdles while creating this,and solved one problem after another.right or wrong, my knowledge can not decide this.but all the code works.
What I can not solve is a mouseout if you touch the on IOS devices.
android devices seems to work great,but i'am unable to solve it for IOS.
the tooltip disapears on -touch but the link has still a hovered state on IOS.
first touch opens tooltip second touch the href link.
i want the second touch on body should reset the href link an next touch should open tooltip again.
and maybe a js guru can give me some hints how i can code this a little smaller.
i made this
(DEMO)
$(document).on('touchstart', function() {
detectTap = true;
});
$(document).on('touchmove', function() {
detectTap = false;
});
$(document).on('click touchend', function(event) {
if (event.type == "click") detectTap = true;
if (detectTap) {
TT_Item_wegmachs();
}
});
and hope for any solution.thx
i found temp solution that helped me,to get IOS mobiles loose hovered on focused element state on body tab.
on "touchstart" i add class to "body" with "cursor:pointer;".
now if i tab on body elswhere,the hovered element on IOS mobiles becomes a "mouseout".
and after that i remove class from "body".
Nevertheless I am happy about better answers
I have been having a little bit of trouble trying to figure this out. I can not get a JQuery .click() event to work on iOS Safari, even after trying some of the known workarounds for this issue.
My code:
HTML:
<div class="mobile-nav-menu">
<a href="#" onclick="void(0)">
<img id="hamburger-menu-icon" src="assets/dot-menu.svg">
</a>
</div>
JS (variable declarations omitted to spare length):
window.onload = () => {
hamburgerMenuIcon.click(toggleMobileNavDropdown);
}
const toggleMobileNavDropdown = () => {
if(mobileNavDropdown.height() == 0) {
mobileNavDropdown.css({
height: '180px',
width: '200px'
})
mobileNavContents.delay(800).fadeIn(900);
} else if(mobileNavDropdown.height() == 180) {
mobileNavContents.fadeOut(400);
setTimeout(() => {
mobileNavDropdown.css({
height: '0px',
width: '0px'
})
}, 400)
}
}
This works absolutely without issue in any browser, both mobile or desktop, other than Safari iOS. I have spent some time on Google and came across a few known work arounds. Here is what I have tried so far without success:
I have tried applying cursor: pointer; to the link. From what I can gather, without this Safari iOS does not register the element as being clickable.
Since adding the cursor CSS property did not work, I tried to add onclick="void(0)" to the HTML as seen in the HTML snippet above. This is another suggestion I came across on Stack, and I am assuming it somehow allows Safari iOS to register the element as being clickable.
On my third attempt, I tried changing the click event to vanilla JS like so and adding touchstart and tap:
hamburgerMenuIcon.on("click touchstart tap", toggleMobileNavDropdown);
So far, nothing gives. Any suggestions?
I do it like this, firstly this part to stop the events happening multiple time due to bubbling from what I do next:
function eventHandler(event, selector) {
event.stopPropagation(); // Stop event bubbling.
event.preventDefault(); // Prevent default behaviour
if (event.type === 'touchend' || event.type === 'touchcancel')
selector.off('click'); // If event type was touch turn off clicks to prevent phantom clicks.
}
Then for the actual element interactions (you don't need the debounce part necessarily, but I find it helpful, if you like I will link you that plugin, is very light weight and helpful):
$(".selection-button").on('click touchend touchcancel', $.debounce(
100,
function(e) {
//whatever you want to do
}));
I have a simple
<a id="eID" href="#showCSSOnlyModalElement">Element</a>.
And I want to introduce some click functionality based on viewport/device size. However, unbinding this click event, disables the standard clickable functionality of the <a> element. I want to retain the default behavior of the <a> element for larger viewport/device.
$( window ).resize(function() {
if ((document.documentElement.clientWidth < 700) || (screen.width < 700)){
$('#eID').click(function(){//hideSomeOtherElements});
}
else {
$('#eID').unbind('click');
}
});
Testing:
Start with large desktop viewport. <a> works fine.
Resize to viewport = 500. The <a> and onClick functionality work fine.
Resize to large desktop viewport. The <a> does not work.
I have tried the .on/.off route also per jQuery documentation. Same result.
Please help.
I probably wouldn't bind/unbind, I'd just check when the click occurs:
$("#eID").click(function(e) {
if ((document.documentElement.clientWidth < 700) || (screen.width < 700)){
// Do something for smaller viewports
e.preventDefault(); // Prevents default behavior of click
// You can also use `e.stopPropagation()` to
// stop the event propagating, or use
// `return false` to do both.
}
else {
// Don't do anything, allow default behavior of click
// (You probably don't need the `else` at all, it's just to make
// clear you're not doing anything here.)
}
});
This is not only simpler, but easier to debug.
Try
function callback {
...
}
$('#eID').bind('click', callback);
$('#eID').unbind('click', callback);
The jQuery API recommends that you specify the callback otherwise bad things could happen.
People!
This is the first time I come here to ask something, so far, always when I had a problem, I could find a good answer here. So, in first place, thanks for this amazing community!
Now let's go to the problem:
I'm doing a responsive menu that check the window.resize event and, when it fits the minimum browser width, a click function for a button is allowed. If the browser width is greater, then the click function is unbound. I need to do this because the same element that is the button on the mobile version, is a visual element on the desktop version.
The problem is that, with the code that I have now, when the page is loaded, the click function works fine. But, if I resize the browser and click on the element again, it triggers more than once the state, sometimes leaving the impression that the function isn't triggered. And, if I resize the browser again, it triggers the click function more than the last time I clicked. Really annoying.
To help understand what is happening, I've made a simple example. Here's is the simple code (just to check the click function issue):
HTML:
<ul>
<li><span class="sub-toggle">Testing 01</span></li>
<li><span class="sub-toggle">Testing 02</span></li>
<li><span class="sub-toggle">Testing 03</span></li>
</ul>
CSS:
.sub-toggle{
display:block;
padding: 20px;
}
.sub-toggle.active{
background-color: #ffcc00;
color: #fff;
}
Javascript (jQuery):
jQuery(function($){
var i = 1;
// check if browser size is compatible with click event
onResize = function() {
// if browser size is ok, do the click function
if($(window).width() <= 480){
// click function
$('.sub-toggle').click(function(){
alert('click');
if($(this).hasClass('active')){
alert('active');
$(this).removeClass('active');
} else {
$(this).addClass('active');
}
});
} else{
// if browser size is greater than expected, unbind the click function
$('.sub-toggle').removeClass('active').unbind('click');
}
// just checking how many times the resize function is triggered
console.log('resize: '+ i);
i++;
}
$(document).ready(onResize);
var timer;
$(window).bind('resize', function(){
timer && clearTimeout(timer);
timer = setTimeout(onResize, 500);
});
});
(Edited to remove some unnecessary code)
If you want to see it in action, I've made a Fiddle (try resize the output frame to see it working): http://jsfiddle.net/C7ppv/1/
Maybe I've missing something really stupid, since I don't have a huge knowledge in JavaScript. But what I want to do is just trigger the click event once, even if multiple resizes.
I hope I could explain well my problem. I've searched and didn't found a solution for this issue (or maybe I just didn't know really well what to look for).
Any help would be appreciated!
Your code currently binds a new click events every time the method onResize is called and the window width is less than or equal to 480px.
Simply unbind any existing click events on the .sub-toggle element before binding a new one.
$('.sub-toggle').unbind('click').click(function() {
...
});
DEMO
The resize event is triggered multiple times during resizing, and each time you're binding a new click handler. My suggestion: bind only once, from outside the resize handler, and set a flag while resizing to let the click handler know if it should do something or not.
Then you won't even need to defer the handling of resize with setTimeout as you're doing.
DEMO
jQuery(function($){
var i = 1;
// flag to allow clicking
var clickAllowed = true;
// click function
$('.sub-toggle').click(function(){
if(clickAllowed) {
alert('click');
if($(this).hasClass('active')){
alert('active');
$(this).removeClass('active');
} else {
$(this).addClass('active');
}
}
});
// check if browser size is compatible with click event
onResize = function() {
//if browser size is ok, do the click function
if($(window).width() <= 480){
clickAllowed = true;
}
else{
// if browser size is greater than expected, disallow clicking
clickAllowed = false;
}
// just checking how many times the resize function is triggered
console.log('resize: '+ i);
i++;
}
$(document).ready(onResize);
var timer;
$(window).bind('resize', onResize);
});
Move $('.sub-toggle').click(function(){...} outside the onResize event handler and move if($(window).width() <= 480){...} into the click handler.