$(function(){
$(".OpenTopMenu").click(function (e) {
$("#top_menu").slideToggle("fast");
e.stopPropagation();
});
$(document).click(function() {
$("#top_menu").hide();
});
$(document).on("touchend", function (event) {
if (!$(event.target).closest("#top_menu").length) {
$("#top_menu").hide();
}
});
});
Hi all, i ran into a strange problem with toggle and hide.
As you can see in my code. If i touch the menu button (.OpenTopMenu) the menu (#top_menu) toggle.
And here its the problem. If #top_menu is visible so when i touch on .OpenTopMenu, #top_menu will hide then toggle to visible again. So i can't really hide #top_menu on touching the menu button (.OpenTopMenu).
Can someone help me with this?
Thanks
Your touchend and click are basically doing the same thing. For mobile uses it's always good to know that a "click" can actually be seen as two events that rapidly follow each other, namely the "mousedown" and "mouseup" event, the last one triggering the "click". On mobile devices, the "click" is triggered at the same time as your "touchend". Now there's also an event called "touchstart" which is triggered when a user put's his / her finger on the glass.
You are right now wondering what all this has to do with your question. Well, it has to do with your document click..
Personally I would solve your problem in the following way;
var userClick = function(){
//you will need something that determines whether your user is
//using a mobile device or not.
return (Browser.isMobile)? "touchend" : "click";
};
var menu = {
isOnMenu:false,
isOnMenu_reset:null,
attachEvents:function(){
$('#top_menu').on('mouseenter',function(){
menu.isOnMenu = true;
}).on('mouseleave',function(){
menu.isOnMenu = false;
}).on('touchstart',function(){
clearTimeout(menu.isOnMenu_reset);
menu.isOnMenu = true;
}).on('touchend',function(){
menu.isOnMenu_reset = setTimeout(function(){
menu.isOnMenu = false;
},30);
});
$('.OpenTopMenu').on(userClick(),function(){
$("#top_menu").slideToggle("fast");
});
$(document).on(userClick(),function(){
if(!menu.isOnMenu){
$('#top_menu').slideToggle("fast");
}
});
},
init:function(){
menu.attachEvents();
}
};
$(function(){
menu.init();
});
Try to change your $(document).click() by somthing like $(".OpenTopMenu").blur(). This might not work with old browsers.
I only wanted click and touched for testing purpose.
But it only have to work with touchend. This is the working code that i finally use. Thanks.
$(document).ready(function(){
$(".OpenTopMenu").click(function(){
$("#top_menu").slideToggle("fast");
});
});
$(document).on("touchend", function(event){
var $trigger = $(".OpenTopMenu");
if($trigger !== event.target && !$trigger.has(event.target).length){
$("#top_menu").slideUp("fast");
}
});
I tried earlier with
!event.target.hasClass('OpenTopMenu') instead of $trigger !== event.target
in the if condition but it doesn't work. Can someone tell me why the upper code work and this one not?
Related
Sorry for the vague project title but I'm not having a great idea about how to explain this.
So, let's dive in to it. I was in need of a dropdown list with multiple select options to select recipients from.
I've started my search on Codepen and came across this: https://codepen.io/MaartenTe/pen/mXYLXj
I've forked it so I could tweak it myself. The snippets works perfect. The only thing missing is the ability of closing the dropdownlist when clicking outside of it.
So I started to approach it using javascript. So far I got following code:
$(document).click(function(e) {
var target = e.target; //target div recorded
if (!$(target).is('.multi-select ') ) {
$('.multi-select-options span').css('display', 'none');
$('.multi-select-options label').css('display', 'none');
}
});
Although this isn't working the way I want, I think it's the right approach?
Looking at how that works, its a checkbox that causes the toggle so you need to clear that when you click out the box.
$('.multi-select').on('click', function(e){
e.stopPropagation()
});
$(window).on('click', function(e) {
$('#toggle-open').attr({checked: false})
});
The stopPropagation will stop the window click even firing. https://codepen.io/anon/pen/rdwrya?editors=1111
What works in the given codepen:
var toggle = document.getElementById('toggle-open');
document.addEventListener('click', function(event) {
if (['INPUT', 'LABEL', 'SPAN'].indexOf(event.target.nodeName) + 1) return;
if (toggle.checked) toggle.checked = false;
});
Just handle click, exclude the relevant elements and uncheck if needed.
I am creating a phonegap application, but as I came to know that it takes 300MS to trigger click event instead of touchevent.
I don't want to apply both event. Is there any way to know if it's touch device without modernizer.
Here is jquery code for assumption
$('#id').on('click',funciton(e){
alert('id was clicked');
});
is there anyway to do it with pure JS/jQuery as phonegap application already takes more memory I want to use less library as I can.
I mean really you should Modernizr but...
var supportsTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints;
var eventType = supportsTouch ? 'ontouchstart' : 'click';
Then declare your event listeners as such:
$('#id').on(eventType, function(e) {
alert('id was clicked');
});
This should eliminate the 300ms delay and trigger simulated clicks on desktop and touch devices :
$('#id').on('mousedown touchstart', function() {
$(this).one('mouseup touchend', function() {
alert('id was clicked');
});
});
If the item has a link in it (normally triggered by click), it would need some adaptation :
$('#id a').on('mousedown touchstart', function() {
var destination = this.attr('href');
$(this).one('mouseup touchend', function() {
if (destination) window.location = destination;
});
});
Edit - already having an accepted answer, this reply was more of an additional note. But nirmal was correct in the comments that touch devices emulating mouse events might lead to complications. The above code is therefore better suited to use with touch events only.
To be more complete with this answer, I'll post my approach for handling both touch and mouse events simultaneously. Either sequence will then trigger a custom event named page:tap. Listening for these simulated clicks can then be done as follows:
$(subject).on('page:tap', function() { ... });
Mouse and touch events are separated and any emulation triggering additional events is prevented by adding a class to body in between touchend and click, removing it again when the latter occurs.
var root = $('body'), subject = '#example_1, #example_2';
$(document).on('mousedown touchstart', subject, function(e) {
if (e.type == 'mousedown' && e.which != 1) return; // only respond to left clicks
var mean = $(e.currentTarget);
mean.one('mouseup touchend', function(e) {
if (e.type == 'touchend' && !root.hasClass('punch')) root.addClass('punch');
else if (root.hasClass('punch')) return;
mean.trigger('page:tap');
});
})
.on('click', subject, function() {
root.removeClass('punch');
return false;
});
One could also choose to add the class to the active element itself or html for example, that depends a bit on the setup as a whole.
Apply fastclick to your application. You'll find a .js file and a documentation over there. The shortest (jQuery) way of implementing that would be:
$(function() {
FastClick.attach(document.body);
});
If you don't use jQuery, you can choose the other way:
if ('addEventListener' in document) {
document.addEventListener('DOMContentLoaded', function() {
FastClick.attach(document.body);
}, false);
}
Let me know if you need further help!
This is the direct link to the fastclick.js file
You can try:
var clickEvent = ((document.ontouchstart!==null)?'click':'touchstart');
$("#mylink").on(clickEvent, myClickHandler);
for anyone coming here in 2021, use pointers events, and check pointerType to distinguish between mouse, touch, and pen.
I'm trying to activate a menu with jQuery with a click (touch) on mobile, but it is not working in mobile. When I do the 'window' resize to try the mobile look, it works with the click, but in an emulator or even trying it with my phone, it doesn't work.
HTML Markup
<img src="i/mobilemenu.jpg" id="mobileMenuButton" style="position:absolute; right:0;"/>
CSS:
#mobileNavigation {display:none}
Javascript Code:
<script type="text/javascript">
$(document).ready(function(){
$('#mobileMenuButton').on('click touchstart',function(){
if ($('#mobileNavigation').css('display') == 'none') {
$('#mobileNavigation').css('display','block');
}
else
{
$('#mobileNavigation').css('display','none'); }
});
});
</script>
Establish a click handler based on the client as such:
var clickHandler = ("ontouchstart" in window ? "touchend" : "click")
and use it whenever you want to listen to click events:
$(".selector").on(clickHandler, function() {...})
This way you can always make sure the proper event is being listened to.
<script type="text/javascript">
$(document).ready(function(){
$('#mobileMenuButton').on('mousedown touchstart',function(){
var userAgent = window.navigator.userAgent;
if (userAgent.match(/iPad/i) || userAgent.match(/iPhone/i)|| userAgent.match(/Android/i)) {
if ($('#mobileNavigation').css('display') == 'none') {
$('#mobileNavigation').css('display','block');
} else {
$('#mobileNavigation').css('display','none');
}
}
});
});
</script>
Just provide the user agent.
I remember when I was building a mobile app, elements that weren't links wouldn't pick up on the click event unless I gave them the CSS property of cursor: pointer. Perhaps this is a similar issue. Try giving the button that property in the style attribute.
Came across this question and realized the click (and touchstart) should work.
#vulcanR, it is not working in your case is because you already have #mobileNavigation as display: none; So, there is no place for the event to be triggered.
Instead, try the following code and it should work-
$(document).ready(function() {
$('#mobileMenuButton').on('click touchstart', function() {
if ($('#mobileNavigation').css('opacity') == '0') {
$('#mobileNavigation').css('opacity','1');
} else {
$('#mobileNavigation').css('opacity','0'); }
});
});
});
The reason behind this working is that opacity:0 retains the height and width of the element whereas display:none makes the dimensions zero, so there is no estate for the event.
You could have also used visibility:hidden, but that doesn't listen to click event or any events in general.
I've tried overflow:hidden but it causes a white flash on each event, there doesn't seem to be a solution. So i'm attemping the javascript way
document.ontouchmove = function(e) { e.preventDefault(); };
and
document.ontouchmove = function(e) { return true; }
But that doesn't seem to work if your already activly on the scroll..
Any ideas people?
cheers!
I don't know if you're using jQuery, but if you do you could try this:
document.ontouchmove = function(e) {
jQuery('.classOrIdOfYourDiv').css({'overflow':'hidden'});
};
Ofcourse you should remove it when the block is release.
Maybe you can give an example in Fiddle?
I have two statements. What I am trying to do is when someone clicks on #area_a then hide then entire #area_b div without activating the focusout for the #area_b_textbox. But I've tried different code (which I am not including here because it is incorrect and want to get your suggestions) and what is happening is it is activating the focusout everytime I click on the #area_a div.
JQuery base actions
$("#area_a").click(function() { $("#area_b").hide(); });
$("#area_b_textbox").focusout(function() {$("#area_b_error").show();});
HTML:
<div id="area_a"></div>
<div id="area_b">
<input id="area_b_textbox">
<div id="area_b_error"></div>
</div>
Thanks!
You could hack around the problem with a timer. Timers usually smell bad but I think it is your safest bet here. If you try using hover or other mouse events you might run into trouble with keyboard navigation and activation or the lack of "hoverish" events on touch interfaces (and we can't pretend those don't exist anymore).
Something like this:
var timer_kludge = {
start: function(fn) {
this.id = setTimeout(fn, 200);
},
stop: function() {
if(this.id)
clearTimeout(this.id);
this.id = null;
},
id: null
};
$('#area_a').click(function() {
timer_kludge.stop();
$('#out').append('<p>click</p>');
});
$('#area_b_textbox').focusout(function() {
timer_kludge.start(function() {
$('#out').append('<p>textarea focusout</p>');
});
});
$('#area_b_textbox').focusin(function() {
timer_kludge.stop();
});
Demo: http://jsfiddle.net/ambiguous/s8kw8/1/
You'd want to play with the 200 timeout a bit to see what works best in your circumstances.
Why not just add a flag to ignore next focusout (blur?) event.
ignoreNextFocus = false;
$("#area_a").click(function() { ignoreNextFocus=true; $("#area_b").hide(); });
$("#area_b_textbox").focusout(function() { if(!ignoreNextFocus)$("#area_b_error").show();ignoreNextFocus=false;});
On that note setting the flag on click event might be too late. If it is the case, try mousedown event.
this is not possible since you loose the focus automatically when you click somewhere else...
What you need to do is to unbind the focusout event on hover of the #area_a and rebind it later on...
$("#area_a").click(function() {
$("#area_b").hide()
}),hover(
function(){
$("#area_b_textbox").unbind("focusout")
},
function(){
$("#area_b_textbox").focusout(function() {$("#area_b_error").show();});
}
)
PS: what is your ultimate goal here?
I'm not sure this is possible since by definition the focus has to leave the #area_b_textbox if the user is going to click a button.