jQuery-ui menu submenu not collapsing on mouseout - javascript

I'm playing around with the Jquery-ui menu widget and I'm trying to get some functionality that seems like it should be REALLY obvious... but I might be overlooking it, or maybe they did when they wrote it.
I was able to get the menu horizontal easily enough, and make the submenu come down vertically... but, for the life of me, I can't get the submenu to collapse when I mouseout of the menu. It just stays there until I click something else. REALLY annoying. As a designer, it goes against all of my sensibilities and I can't see a reason for it to do just hang there.
Did I break the thing, or do I need to add something special?
As a side note, I've been fiddling with the Jquery-ui js for a couple hours, editing the menu widget. I tinkered around here:
// DEFAULT FUNCTION:
// Clicks outside of a menu collapse any open menus
this._on( this.document, {
click: function( event ) {
if ( !$( event.target ).closest( ".ui-menu" ).length ) {
this.collapseAll( event );
}
// Reset the mouseHandled flag
this.mouseHandled = false;
},
// I ADDED THIS:
mouseout: function( event ) {
this.collapseAll( event );
}
});
It produced the behavior I was going for... sort of...
Now I have spotty mouse enter detection for my menu item with the submenu attached. Not really ok with putting a live site up where the menu only works some of the time. Any ideas? Am I doing this the hard way or the wrong way, or is there something I simply don't know about? I'm not the greatest with jQuery, just started in fact.
I'm using a setup that is basically an augmented version of the example on the jQuery UI demo page of the menu widget, so I don't think it's my html that's causing the problem.

I just had the same problem and find the solution here. I hope it works with you.

Ok, this just took some searching.
I used jplfl's example in the previous answer as a guide and went into the jquery-ui.js file, searching for any functions that had to do with the menu. I found line # 9715 where mouseleave was bound to "collapseAll" instead of calling a function which actually collapsed the menu. I changed it to this:
mouseleave: function( event ){
this.collapseAll( event, true );
},
And now it works.
So, Yeah. jplfl's answer was definitely helpful, but I thought this might be pertinent as it goes into a little more detail.

Aaron:
Just search for 'ui.menu' and scroll down till you see
mouseleave: "collapseAll"
line, for me it is 11507 (jquery-ui-1.10.3)

I'm not sure if this will work:
$(document).ready(function() {
$(“#menu”).menu({
mouseleave: function( event ){ this.collapseAll( event, true ); }
});
But I'm sure there is another option.
You may check this link:

Related

JQ UI Draggable on iOS: initiating dragging in taphold-handler

In our app we want to drop from one list to over. Problem is, when there are many items in list - it's impossible to scroll when elements are dragable.
As workaround we want to disable drag-ability of elements and enable it only when user makes a long tap on an element.
$('li').bind('taphold', function (event, ui) {
console.log('taphold');
clearAll(); // clearing all other catched
$(this).addClass('catched')
$(this).draggable('enable');
});
here is jsfiddle https://jsfiddle.net/nrxaqc34/10/
So far it works, but user needs to tap once more in order to drag. And would be nice if user could start dragging right after long tap.
This answer here https://stackoverflow.com/a/9922048/582727 doesn't work on iOS.
Maybe someone has an idea.
Does it make sense to use delay option? http://api.jqueryui.com/draggable/#option-delay
$("li").draggable().draggable( "option", "delay", 2000);
Fiddle: https://jsfiddle.net/dob3uegj/
EDIT:
jqueryui-touch-punch (http://touchpunch.furf.com/) added to fiddle for smartphone simulations:
https://jsfiddle.net/dob3uegj/1/

Ignoring mouseenter/mouseout events on children of same element in JS

I am using this menu (http://tympanus.net/codrops/2013/04/17/slide-and-push-menus/) in my website and I modified it slightly. Instead of using the button to show and hide the menu I want to show the menu when the mouse enters a region of the menu and disappears when the mouse leaves the menu. I managed to achieve showing the menu on mouseenter, however, whenever hovering over a child the menu just keeps showing and hiding itself. The JS code can be seen in the snippet below.
showLeft.onmouseover = function() {
classie.toggle( this, 'active' );
classie.toggle( menuLeft, 'cbp-spmenu-open' );
};
I made some research and from what I understood is that this phenomenon is referred to as 'bubbling' and I tried filtering the trigger of the event by the source of the event however I was not successful. Any help would be greatly appreciated.
Yes, this is caused by event bubbling as you identified.
The simplest way to solve your problem is to use jQuery, which specifically handles this case through its mouseenter/mouseleave events.
$(elem).on("mouseenter", function() {
// your code
});

Scroll event for Meteor

I couldn't find a scroll event for meteor in the meteor docs. How do I go about doing something as someone scrolls the window down in a meteor application?
I've tried 'scroll window' : function(event) { ... } which doesn't work as expected.
I've been messing around with this as well.
I haven't found a way to do it cleanly within Template.template.events.
The obvious temporary solution right now would be using a simple jQuery scroll event.
$(window).scroll(function(){//your code}); should do the trick.
Things I was trying to use as the selector but to no avail were:
'scroll *'
'scroll body'
'scroll document'
and naturally
'scroll window'
I tried all of these selectors inside of a generic template's events, along with on UI.body's events, as that's the new blaze template that encompasses the page's body.
To reiterate: You're probably better off using jQuery for the time being.
This is a bit late but I came up with a solution; at least in the context of my current project.
I'm implementing D3 with Meteor, and I wanted a custom zoom functionality that changes the template's dimensions when the user scrolls.
Create a reactive variable 'zoom'
Template.graph.onCreated(function() {
var self = this;
self.zoom = new ReactiveVar(0);
$(window).on('scroll', function(e) {
// ... event processing stuff;
// say it produces value 'zoomAmount' ...
self.zoom.set(zoomAmount);
}
});
Create a helper that returns zoom.
Reference it in the template DOM in a hidden element to make it reactive.
Template.graph.helpers({
zoom: function() {
// This will be called when 'zoom' changes,
// so treat this as your events function
return Template.instance().zoom.get();
}
});
In Meteor there is no native template support for scroll events, so you have to do within your Template.name.onRendered callback. However, you will get a memory leak if you don't remove it from Template.name.onDestroyed. This is best accomplished with namespaced events, since something like $(window).off('scroll'); will detach all scroll events from window.
import { $ } from 'jquery';
Template.myTemplateName.onRendered(function(){
// You can do this multiple times
$(window).on('scroll.whateverNamespace', function() { ... });
$(window).on('scroll.whateverNamespace', function() { ... });
})
Template.myTemplateName.onDestroyed(function(){
$(window).off('scroll.whateverNamespace');
})
This is really late at this point, and I assume much has changed since the question was asked, but I came across this problem myself, and for anyone else that may need to know, the method that I found to work was to create a helper called 'scroll .container' where the container is a div that contains the main body of the page (where the user would scroll in my application) My function looked something like this :
Template.main_page.events({
'scroll .container': function(event) {
console.log(event.currentTarget.scrollTop);
}
});
As a partial solution, you can listen for the mousewheel event on whatever element you care about. A lot of times this is exactly what you want anyways.
As an example, the following event listener will prevent the user from scrolling with the scroll wheel at all, but they will still be able to use the navigation bar on the side of the page. (If you have not disabled it with overflowy: hidden;)
Template.body.events({
'mousewheel': function(event, template) {
console.log("scrolled");
return false;
}
});

Dropdown plugin closing on scroll bar click

I'm in the process of teaching myself how to write a jQuery plugin. I am using the jquery-hover-dropdown-box as a base example. It's not just copy/paste though, I've made a number of changes trying to get a better understanding of it all. For example I'm not incorporating the hover event, I added a filter, and currently not using any defaults to name a few. Clicking on a div's scroll bar fires the blur event in I.E is the only post I've found with what looks like a good resolution to this and I tried implementing something similar but was unsuccessful.
Complete Example: jsFiddle
Issue:
I click in the input and the dropdown opens but the first time I click on the scroll bar, the dropdown closes. When I open the dropdown a second time and click on the scroll bar, it does not close (as I would expect). From what I can tell, my issue is in the blur on the input. I understand that when I click in the scroll bar, the input has lost focus. I tried to implement something similar to this post on Scrollbars not working on dropdown in IE8 but was unable to get it working.
Steps to Reproduce:
Click in the input to open the dropdown
Click anywhere in the scroll bar and the dropdown closes (should stay open and scroll)
Click in the input a second time and the dropdown opens
Click anywhere in the scroll bar and the dropdown stays open (as it should)
Question:
What am I doing wrong that is causing the dropdown to close only the first time I click on the scroll bar?
What I've Tried:
When I'm appending the ul to the div (currently commented out around line 68 in the jsFiddle), I added the code below. I figured that if I stopped the action from being triggered with a mousedown on the ul it would fix my issue. Although it did fix the issue in Chrome, it persists in IE8.
Update: I changed the code below from $list.mousedown... to $container.mousedown... since $list is the ul and $container is the div that contains it. My thought was that it extend the area. The result was the same though.
...
$container.append($list);
$list.mousedown(function(e) {
e.preventDefault();
});
...
Since this seemed to be close, I tried taking a similar approach in the blur event. The issue explained above happens when I use this code. In Chrome, clicking the scroll bar does not fire the blur event but in IE8, it does. The first time the dropdown is opened and you click in the scroll bar, it logs "hiding". Open the dropdown again and click the scroll bar and it logs "bind mousedown". Click anywhere outside the dropdown and it closes (as it should) and logs "hiding" (as it should). To me it seems backwards, but obviously I'm not understanding it correctly. (The code below is around line 134 in the jsFiddle)
Code edit: Updated with Goran.it suggestion to prevent multiple bindings from happening.
...
// where $dom is the 'div' containing the 'ul'
$dom.unbind('mousedown.auto_dropdown_box_ul')
.bind('mousedown.auto_dropdown_box_ul', function(e) {
console.log('bind mousedown');
e.preventDefault();
});
setTimeout(function() {
console.log('hiding');
$dom.addClass('auto_dropdown_hide').hide();
}, 100);
...
I've also tried removing the blur event. I know this would prevent the dropdown from closing if you tabbed out of the input but figured it was worth a try. In Chrome it works exactly how I expected, clicking outside the input closes the dropdown, clicking the scroll bar does not close it and tabbing out does not close it. In IE8, clicking outside the dropdown does not close it though, nor does it close when you tab out, but clicking in the scroll bar does work. This is the code I added after removing blur (it's not included in the jsFiddle).
// below where the 'blur' event was
$(document).click(function(e) {
if (e.target == dropdownArray[0].input[0] || e.target == dropdownArray[0].dom[0]) {
console.log('matches');
e.preventDefault();
} else {
console.log('does not match');
dropdownArray[0].dom.addClass('auto_dropdown_box_hide').hide();
}
});
Again, this is my first attempt, I'm still learning. I'm sure there are multiple things that I'm probably doing wrong, that I can improve, etc. Before I tackle those, I would just like to understand what I'm doing wrong here and what I need to do to correct it. After reading the plugin concepts, I know there is much for me to learn.
I found few issues on a first look, you should change the :
$dom.bind('mousedown.auto_dropdown_box_ul'
to:
$dom.unbind('mousedown.auto_dropdown_box_ul').bind('mousedown.auto_dropdown_box_ul'
To prevent multiple events binding to the dom node, you can also use .one event handling of jQuery.
In the same event handling you should also put:
console.log('bind mousedown');
e.preventDefault();
return false;
To be sure event is not firing.
Hope this helps (I'm not having IE8 for a long time now)
I believe I finally figured this one out. After multiple tries I thought I'd change up the format to one that seemed, at least to me, a little more straight forward.
Here is the complete jsFiddle
The underlying fix was correctly setting/adjusting which element has focus and when. Since mousedown executes before click, I stuck with that event on the dropdown. In the mousedown event, I set isVisible = true and set focus back on the input (although the latter is not completely necessary). In the blur event, I'm checking isVisible. If it's true, that means that a click happened in the scroll bar so don't close the dropdown. If it's false, close the dropdown. Throughout events, I'm keeping track of isVisible so I know it's state when blur executes. Again, I changed up the format so the two fiddles do look different. I'm sure I could go back and implement something similar to the original fiddle and get it working but I just liked this way more. Here is a snippet of the relevant changes:
{
// some code above
// where $list is the 'ul'
$list.bind('mousedown', methods.onDropdownMousedown);
// where $obj is the 'input'
$obj.bind('blur', methods.doOnBlur);
},
onDropdownMousedown: function(e) {
$input.focus(); // not really needed, just in case
isVisible = true;
},
doOnBlur: function(e) {
if (isVisible) {
$input.focus();
isVisible = false;
} else {
// where $container is the 'div' containing the list
$container.addClass('auto_dropdown_box_hide').hide();
isVisible = false;
}
isVisible = false;
}

Trigger Javascript click/touch event only if NO other events are simultaneously triggered?

I'm trying to make a navigation menu which is hidden from view but that which appears by touching/clicking on the screen.
The problem I see is that touching/clicking many places on the screen could open the navigation menu while simultaneously triggering an event on whatever button, link, etc. that might have been in the vicinity.
So far, I'm trying to handle this with a :not clause in jQuery. Unfortunately there is something not work with the :not clause as the toggling happens regardless of where you click within the body.
HTML:
<div id="NavigationMenu">i'm the navigation menu</div>
<div class="icon-reorder">toggle</div>
<div id="main_content">i'm the main content
<button type="button">button</button>
</div>​
JS:
$(document.body).on('click', ['body:not(".btn, a, i, button, input, textarea")', '.icon-reorder'], function(){
console.log('clicked');
$('#NavigationMenu').toggle();
$('#main_content').toggle();
});
$('button').on('click', this, function(){
console.log('button clicked');
});
Might someone be able to help with this code? Or is this even the right way to go about solving this problem? It looks a little hack-ish to me.
This navigation menu is the main one for my site so having an annoying UI/UX (nav opens too much/too little) is a deal breaker. I mainly interested in touch compatible code but any and all UI/UX suggestions would be welcome...
Instead of using a :not clause, why not use event delegation (which, I only learned two months ago, is a fancy term for handling the events with a callback, on a parent element)
$(body).on("click", function(event) {
if(event.target.type !== "button" && <whatever other conditions>) {
<toggle menu>
}
});
Here's an updated Fiddle . I'm logging the click event object to the console so you can look at event.target and see if there's anything more suited to your needs to compare to

Categories