Working in HTML, CSS and JS (technically Angular, if you think it's significant)
I have a Header menu with dropdown sub-menus and sub-sub-menus when viewed in desktop style.
On a PC the sub-menus appear on hover and clicking on the entry takes you somewhere.
Clicking on the root entry takes you somewhere different - so it has 2 purposes in life: be a link to a location AND be the hover trigger for the dropdown menu.
Not all root elements have a sub-menu.
There's a separate mobile menu, based on width media queries, but Tablets (especially in landscape mode) display in desktop style, and it's giving me gyp!
On tablets (tested in Safari iOS and in Chrome for iPad) the browser does some deep magic!...
For elements that have No dropdown then clicking on them takes you to
the link.
For elements that DO have a dropdown sub-menu, then
the first click has the effect of activating the hover - it doesn't activate the link but does reveal the menu.
The second click then activates the link.
Lovely!
Problem is... the menus don't disappear if you tap off them.
Tapping the page in general does nothing (no click-event raised)
Tapping something on the page that is clickable DOES clear the menu, and also invokes the click action for whatever you clicked.
My first thought was to put a transparent div across the whole rest of the page, above the page but below the menu, and bind a click event that would clear the menu.
But, I can't get the transparent layer AND the underlying page to both be clicked. See here for the problems I hit there.
Putting the click event on body (so that it gets triggered by bubble up) doesn't work (click event just isn't fired.)
I tried adding ngTouch, and that does cause click events to be triggered everywhere, but also breaks the behaviour of the sub-menus opening - all the links trigger immeidately and you can't reach the sub-menus.
Any thoughts at all? Help!
You just need to check if click happened outside of dropdown menu.
Something like:
$('html').click(function (e) {
if (e.target.id == '#yourDropdown') {
//do nothing and let the click be handled
} else {
$('#yourDropdown').hide();
// still let the click be propagated
}
});
Rather then relying on 'mobile browser magic' I would implement it myself. No Angular experience, but in jQuery the code would probably look something like this:
$('.menu li').on('click', function(e) {
var $target = $(this);
var $sub = $target.children('ul');
// only if sub and not yet active
if ($sub.length && ! $target.hasClass('active')) {
// show sub
$target.addClass('active');
// done
e.stopPropagation();
return false;
}
// normal click action triggered here
alert($target.children('a').text());
e.stopPropagation();
});
$('html').on('click', function(e) {
// clear all active menu items
$('.menu > li.active').removeClass('active');
});
And a quick example: http://jsfiddle.net/b0aqr1wc/
:Sigh:
A colleague I discussed this with this morning solved this instantly:
Use the "cover sheet" approach, but have the sheet collapse itself at the same time as collapse the menu.
You lose the ability to interact with the underlying page for only 1 tap - and that tap will visibly collapse the menu, so the user will have a prompt to try again.
Related
I am having the following issue with click/touchstart event on Android (as far as I know only happening on Android),
1. the element triggers a modal window.
2. one of the buttons/links inside this modal gets triggered instantly without giving the user the option to make a choice.
It is of course required for the visitor/user to view the modal content before being redirected to a link to another page from one of those buttons.
I believe this is due to the 'touchstart' event bind to this div, which I am using since click events on divs for touch devices don't work.
I am using jQuery to make this work, and on iOS there doesn't seem to appear any issue.
$(document).on('click touchstart','.mydiv', function(e) {
e.preventDefault();
// open modal
});
Any suggestions please.
Try this:
$(.mydiv).on('touchstart', function(e) {
e.preventDefault();
// open modal
});
cheers
I'm trying toggle a DIV element using jQuery, a good example of this implemented is clicking the sign up button on Udemy.
I've implemented something similar using jQuery but I'm sure that to gain the effect I'm looking for, I will have to use JavaScript but its just that I'm don't know how to use JavaScript.
The my implementation be seen in my fiddle here, I've initially set the div to display:none and used jQuery to show the div on button click.
As you can tell with the fiddle, it displays with an enlarging animation instead of just appearing (not sure how to change this) and i'm only unable to make the div disappear by again clicking the button.
Also, how would I go about implementing functionality to make the div disappear by clicking anywhere on the screen?
Thanks to anyone in advance for taking the time to help me out.
The issue you face is that a click on the button is also a click on an area where you would like the pop up to disappear, if it's already shown. Because events bubble, the button click would make the pop up appear and then the document click (which fires after this because of bubbling) would make the pop up immediately disappear.
To solve the problem, you must stop a click on the button from bubbling to the rest of the document as well. You do this with:
event.stopPropagation();
So, what you need to do is make sure that when the button is clicked, the click event doesn't bubble up to the document, where you will have already set up a click event handler that makes the pop up go away:
$(document).on('click', function(event) {
// We want to hide the pop up, but not if you click on
// the pop up itself - - anywhere else, but not the pop up
if(event.target.id !== "pop-up"){
$('#pop-up').hide();
}
});
See this fiddle for a working version: https://jsfiddle.net/0ajpd9go/8/
If you want your div to just appear on the screen change this line:
jQuery('#pop-up').toggle('fast');
to this:
jQuery('#pop-up').show();
Maybe you'd like to give bootstrap modal a try:
http://getbootstrap.com/javascript/#modals
I think what you are looking for is $.fn.toggle();
$.fn.toggle(); toggles the visibility of an element meaning if the element is visible then it will be hidden when toggled and if the element is hidden it will be shown when toggled.
Here is a basic (animation free) example of using toggle:
$(".button-that-toggles").on("click", function() {
$(".div-to-toggle").toggle();
});
Your box toggles with an "enlarging animation" because you used $.fn.slideToggle();
There are three default ways to toggle using jQuery (toggle, fadeToggle and slideToggle)
Here is an example of toggling a element using $.fn.fadeToggle();:
$(".button-that-toggles").on("click", function() {
// NOTE: 250 represents the duration of the animation, meaning that the animation will last 250 milliseconds.
$(".div-to-toggle").fadeToggle(250);
});
Here is an example of toggling a element using $.fn.slideToggle();:
$(".button-that-toggles").on("click", function() {
// NOTE: 250 represents the duration of the animation, meaning that the animation will last 250 milliseconds.
$(".div-to-toggle").slideToggle(250);
});
Also here is an example of how you can hide your div by clicking anywhere on the page:
// listen for a click anywhere in the page
$(document).on("click", function(event) {
// make sure the element that was clicked is not your div
if(!$(event.target).is(".your-div")) {
// you can now hide your div
$(".your-div").hide();
}
});
Also please remember that jQuery is JavaScript as a matter of fact jQuery is a library written in JavaScript.
I want to create a mouseover dropdown navigation (which works with tap on mobile/ipad as well) and have the problem, that the menu itself is in a complete different div. So not a child of that element.
jQuery('.top-menu').on("mouseover",function(){
jQuery(".top-menu-dropdown").stop().slideToggle(200,'easeOutCubic');
});
The div which is triggering that the menu slides down is .top-menu once hovered but I have the problem that I have to add the top-menu-dropdown class to it so it's closing as soon as the user exits the menu. And how can I add a short delay that the menu is not closing as soon as the cursor leaves it? (Stopping timer when you enter it again ofc)
I would write it more like this using the jquery hover function which has both the mouse over and mouse out built in as shown below.
jQuery('.top-menu').hover(
// Mouseover
function(){ jQuery(".top-menu-dropdown").stop().slideDown(200,'easeOutCubic'); },
// Mouseout
function(){ jQuery(".top-menu-dropdown").stop().slideUp(200,'easeOutCubic'); }
);
Replcace slideup and slidedown with whatever direction you would like :)
In the jQuery autocomplete/menu widget (the autocomplete widget is based on the menu widget, which is a still unreleased widget), how is a click outside of the menu detected ? (A click outisde of the menu closes the menu)
I have added a srollbar (similar to the classic select element) to that menu in a custom combobox widget I am writing. The problem is that in IE8, a mousedown on the scrollbar is detected as a click outside the menu, which closes it, making the scrollbar useless. So, to work around this issue, I am first trying to understand how the menu widget works.
You can view the source here, it's basically just checked when it's blur event fires, and hiding 150 seconds after, if the click wasn't in the menu portion:
.bind( "blur.autocomplete", function( event ) {
clearTimeout( self.searching );
// clicks on the menu (or a button to trigger a search) will cause a blur event
self.closing = setTimeout(function() {
self.close( event );
self._change( event );
}, 150 );
});
Other areas of autocomplete, e.g. the selection menu itself clear this timeout, preventing the hide...a blur caused by something else doesn't, resulting it in being hidden. It's worth noting this is not the way for you to replicate the behavior, there are better ways by preventing bubbling, but if your goal is to understand this widget specifically...well that's what it does :)
It would be easier to dismiss the menu not after a click but if the mouse leaves the menu (after a short grace-period).
I find myself very often in the situation that I open an element in a web page - e.g. a drop-down menu - that I want to close if the user clicks anywhere on the page except the element itself.
To keep things simple, I have mostly written the code myself instead of employing some drop-down menu class.
However, I have never managed to build an implementation of this that was completely satisfying: Event handling and bubbling would work differently in different browsers, there would be the need for nasty workarounds, in some situations clicking the drop-down button would start closing it in the same moment, and so on.
Is there a Prototype based, authoritative, best practice to do this? Something that works across browsers - IE6 being a plus but not a requirement?
Just this:
click on a button - an element opens
(e.g. an absolutely positioned drop-down menu).
click within the element - the element stays open.
click on the button that opened the element - the element stays open.
click anywhere else on the page - the element closes.
I need help with the event handling part only, the displaying of the menu is totally secondary.
Event.observe(document, 'click', function (event) {
switch (event.element().id) {
case 'example_id':
// do different stuff depending on element clicked
// ofc u don't need to pass id, u can simply throw an element itself
break;
default:
// do close action
break;
}
// also check Event.findElement();
});
You can also add specific classes to the items you don't want to trigger close action and check it inside
if (!event.element().hasClassName('dont_close'))
Element.remove(selectDOMElement);
I guess the open button is within the menu.
$('openbutton').observe('click' function(event) {
var menu = $('openbutton').up();
if (menu.hasClassName('collapsed')) {
menu.removeClassName('collapsed');
menu.addClassName('expanded');
document.observe('click', function (event) {
if(!event.target.descendantOf(menu)) {
menu.addClassName('collapsed');
menu.removeClassName('expanded');
}
});
} else {
menu.addClassName('collapsed');
menu.removeClassName('expanded');
}
});
AFAIK, you need to make an invisible div the size of window, put it behind the current element, and add a click event to that.
Just thinking out loud but you might be able to use the blur event on the dropdown to hide it (blur gets fired when an element loses focus) or another idea might be when the dropdown opens attach a click event to the document object that hides the dropdown. Events get propagated through their containers so it should end up at the document object eventually. You might need to call preventPropegation on the event when your dropdown gets clicked so that it doesn't make it to the handler attached to the document.
maybe you could calculate the Position (X,Y) for the clickevent and compare that to the cumulativeOffset (cumulativeScrollOffset) + [el.width|el.height] of the desired container.
Event.observe(window, 'click', function(e) {
var el = $('el')
if( el.cumulativeOffset[0] < e.Event.pointerX(e) ... )
});
<div id="el" style="position:absolute;width:100px;height:100px;background-color:#00F;top:100px;left:300px;">
</div>