How to unbind() .hover() but not .click()?
Asked Answered
D

2

3

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/

Denture answered 15/6, 2014 at 20:1 Comment(4)
I don't understand why JS will work if CSS won't. Can you help me to understand how your mouseenter / mouseleave on the .dropdown class behaves any differently from .dropdown:hover? What am I missing here?Jarvis
Actually, css DOES work. It's just that I can't use it because of my design constraints. Basically, there is a 'gap' between the link and where the dropdown appears, so that when the user would try to go to the dropdown (after it has appeared when the user hovers over the link), the dropdown disappears, because naturally the link doesn't remain in the hover state, because the user goes over that gap to reach to the dropdown.Denture
I understand that. So, the same will happen if you hide the menu on mouseleave ... that's the part I don't get. I mean you don't actually show what you're doing in the handlers but what you have there appears as though it will produce the exact same behavior, no? Are there missing functions? Maybe handlerOut is what I'm missing and how the hideMenu actually works.Jarvis
That last jsFiddle seems to do the job. This has been an interesting problem to try and solve... glad you figured it out.Fairspoken
F
2

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.

Fairspoken answered 15/6, 2014 at 20:34 Comment(8)
Hi. Thanks for you answer. I think I've got really close to the solution; however, please see my updated question for the problem that I'm facing when the window resizes.Denture
That's because the bindings have already been applied; resizing the viewport is not a page request, so the DOM doesn't change.Fairspoken
So how can I do it so that the hover() function on that element only works on devices larger than 800px?Denture
@Denture Try the edit above; notice the change from .hover to .on, then we use .off to remove those handlers if the viewport doesn't match anymore.Fairspoken
Nah, it's still behaving the same way, doesn't switch to the other one when the window resizes.Denture
@Denture Okay, here's a jsFiddle I started: jsfiddle.net/CR2Lw/1. Update it to include a pared-down version of what you're doing and then post the link to the updated version in your question.Fairspoken
I'm actually trying to have Bootstrap dropdown appear on hover instead of click. Please see my updated answer for the updated jsfiddle and thanks :)Denture
Let us continue this discussion in chat.Fairspoken
J
2

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!

Jarvis answered 15/6, 2014 at 23:56 Comment(3)
Hi! Thank you so much for your answer. Your first answer where you checked for the .toggle display helped me to find a solution. Please check my last update. Unless I'm missing something, I think it's working perfect.Denture
Oh, thank goodness you posted your solution...it was driving me crazy! Clever, btw, I didn't think of putting a timer on it. I like it very much. I think I'm going to delete the css option in my answer to keep it concise.Jarvis
Hey, why don't you add a link to your answer to the final fiddle so that I can mark it as correct answer.Denture

© 2022 - 2024 — McMap. All rights reserved.