1

I have an issue with mouseleave and hover on devices that supports both Pointer and Touch events. These devices include laptops with a mouse and touchscreen.

I basically just want to disable mouseleave and hover, but the problem is it is a device that supports both and I can't find an article explaining this properly and there are no standards.

I had a look at the following links:

Disable hover effects on mobile browsers

How to remove/ignore :hover css style on touch devices

jquery preventing hover function on touch

jQuery mouseleave for touch screen / tablets

Disable hover effects on mobile browsers

We are using DNN (DotNetNuke) as a Content Management system. I know that you can build custom menu's using tokens and DDR menu's, but this is too complex for what I want to achieve.

My simple approach was to build the sub-menu from data fetched from our ERP database and display it when you hover over a DNN page link which is "disabled" with a certain name that matches using jQuery.

Everything works fine on a Desktop Device. It also works with a Touch & Pointer device using Chrome.

I am having an issue with Edge on a Tablet Device with Touch and Pointer events. The onmouseleave is fired when you tap on "Categories" which will cause the sub-menu to close. When you tap on the "Categories" menu, it fires the hover event.

What makes it more difficult is that the Sub-menu is not a direct child of the parent, so it is not always easy to use CSS selectors. Currently I place the module beneath the menu so that it is at least very close so that I can use Absolute and Relative positioning to get the sub-menu to display directly below the links. This is where you will notice that I have added a timeout function on the one mouseleave event to allow someone to navigate to the sub-menu when their mouse leaves the hover event.

Here is a screenshot of the menu. It contains sub categories which can show, but I just want to get the main menu showing properly on devices with both Touch and Point event support.

enter image description here

Example JSFidle Code

JSFidle: https://jsfiddle.net/Tig7r/e6k9cfj1/13/

HTML

<nav class="NavMenu">
  <ul class="ul_menu">
  <li class='item'><a href="#"><span>Home</span></a></li>
  <li class='item'><a><span>Categories</span></a></li>
  </ul>
</nav>


<div class="subLevel MegaMenuDiv" id="MegaMenuDiv">
  <div class="custom_megamenu_wrapper">
   <ul class="main-category-list has-children"><li><a href="javascript:void(0)" class="Parent_Mega_Menu_Categories MegaMenuLinkMainWithChildren" style="">Accessories</a>
      <ul class="secondary-items">
      <li><a href="https://www.google.com" class="MegaMenu_Child_Link" style="">Accessory Holders</a></li>
      <li><a href="https://www.google.com" class="MegaMenu_Child_Link" style="">Whiteboard Starter Pack</a></li>
   </ul></li>
</ul>
 </div>
</div>

css

.NavMenu{
  width:100%;
  height:40px;
  background-color:red;
  color:white !important;
}

.NavMenu ul li{
  list-style:none;
  display:inline-block;
  padding:10px;
}

.ul_menu li a:link{
  color:white;
}

.ul_menu li a:hover{
  color:black;
}

#MegaMenuDiv{
  background:black;
  color:white;
  position:absolute;
  width:550px;
  display:none;
  min-height:300px;
}

.MegaMenuDiv a:link{
  color:white;
}

.displayHiddenMenu{
  display: block !important;
}

.main-category-list li{
  list-style:none;
}

.secondary-items{
  background: #31383e;
  position: absolute;
  top: 0;
  left: 150px;
  width: calc(80vw - 50%);
  height: auto;
  list-style: none;
  /* padding: 20px; */
  display: none;
  height: 92%;
  overflow-y: auto;
  padding-top: 0px;
  z-index: 1000;
  max-width: 840px;
  padding-top: 13px;
  line-height: 2;
}

.secondary-items a:link, .secondary-items a:visited{
  color:white !important;
}

JQUERY

$(document).ready(function () {

$(".item:contains(Categories)").hover(function () {
        if ($('.MegaMenuDiv').hasClass('displayHiddenMenu')) {          
        } else {
            console.log('No class, adding class');
            $('.MegaMenuDiv').addClass("displayHiddenMenu");
        }
    }); 

 /* Removes the submenu when the mouse moves away from categories */
 $('.item:contains(Categories)').on("mouseleave", function (event) {
       if ($('.MegaMenuDiv:hover').length > 0) {
       // do nothing
       } else {             
                $('.MegaMenuDiv').removeClass("displayHiddenMenu");
       }
});

$(".item:contains(Categories)").hover(function () {
    if ($('.MegaMenuDiv').hasClass('displayHiddenMenu')) {
      console.log('Item has class');
    } else {
      console.log('No class, adding class');
      $('.MegaMenuDiv').addClass("displayHiddenMenu");
    }
});

  $(".item:contains(Categories)").on("touchstart click", function () {
    if ($('.MegaMenuDiv').hasClass('displayHiddenMenu')) {
      $('.MegaMenuDiv').removeClass("displayHiddenMenu");
    } else {
      $('.MegaMenuDiv').removeClass("displayHiddenMenu");
      $('.MegaMenuDiv').addClass("displayHiddenMenu");
    }
  });

  $('.MegaMenuDiv').on("mouseleave", function () {
    console.log('Mouseleave remove class');
    $('.MegaMenuDiv').removeClass("displayHiddenMenu");
  });

//Code for child menu elements
  $('.MegaMenuLinkMainWithChildren').hover(function () {
        if ($(this).next().hasClass('displayHiddenMenu')) {
                //do nothing
        } else {
            $('.MegaMenuLinkMainWithChildren').next().removeClass('displayHiddenMenu');
            $(this).next().addClass('displayHiddenMenu');
        }
});

$('.MegaMenuLinkMainWithChildren').on('touchstart click', function () {
        var secondaryitems = $(this).next();        
        if ($(secondaryitems).hasClass('displayHiddenMenu')) {

        } else {
            $('.MegaMenuLinkMainWithChildren').next().not(secondaryitems).removeClass('displayHiddenMenu');
            $(secondaryitems).addClass("displayHiddenMenu");
        }
});

});
Tig7r
  • 525
  • 1
  • 4
  • 21

2 Answers2

2

He's a better workaround the issue. I have listen to clicks mouseevents and touchevents. Therefor hopefully should work on any device. However I didn't test this on Edge. Hope it helps.

You may also listen to all .NavMenu .item elements and hide the .MegaMenuDiv if it's not Categories item, because someone might accidentally hover the categories item.

// main menu
$(".item:contains(Categories)").on('mouseenter touchstart click', function(e) {
 
 // toggle MegaMenuDiv on click
 e.type == 'click' ? $('.MegaMenuDiv').toggleClass("displayHiddenMenu") : $('.MegaMenuDiv').addClass("displayHiddenMenu");
});

$('#MegaMenuDiv').on('click', function(e){
 if(e.target == $('#MegaMenuDiv').get(0)){
   $('.MegaMenuLinkMainWithChildren').next().removeClass('displayHiddenMenu');
  }
}).on('mouseleave', function(){
  $('#MegaMenuDiv .secondary-items').removeClass('displayHiddenMenu');
 $('#MegaMenuDiv').removeClass("displayHiddenMenu");
});

// MegaMenuLinkMainWithChildren
$(".MegaMenuLinkMainWithChildren").on('mouseenter touchstart click', function() {
 // toggle MegaMenuDiv
  $('.MegaMenuLinkMainWithChildren').next().removeClass('displayHiddenMenu');
  $(this).next().addClass('displayHiddenMenu');
});
.NavMenu{
  width:100%;
  height:40px;
  background-color:red;
  color:white !important;
}

.NavMenu ul li{
  list-style:none;
  display:inline-block;
  padding:10px;
}

.ul_menu li a:link{
  color:white;
}

.ul_menu li a:hover{
  color:black;
}

#MegaMenuDiv{
  background:black;
  color:white;
  position:absolute;
  width:550px;
  display:none;
  min-height:300px;
}

.MegaMenuDiv a:link{
  color:white;
}

.displayHiddenMenu{
  display: block !important;
}

.main-category-list li{
  list-style:none;
}

.secondary-items{
  background: #31383e;
  position: absolute;
  top: 0;
  left: 150px;
  width: calc(80vw - 50%);
  height: auto;
  list-style: none;
  /* padding: 20px; */
  display: none;
  height: 92%;
  overflow-y: auto;
  padding-top: 0px;
  z-index: 1000;
  max-width: 840px;
  padding-top: 13px;
  line-height: 2;
}

.secondary-items a:link, .secondary-items a:visited{
  color:white !important;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<nav class="NavMenu">
    <ul class="ul_menu">
        <li class="item">
            <a href="#">
                <span>
                    Home
                </span>
            </a>
        </li>
        <li class="item">
            <a>
                <span>
                    Categories
                </span>
            </a>
        </li>
    </ul>
</nav>
<div class="subLevel MegaMenuDiv" id="MegaMenuDiv">
    <div class="custom_megamenu_wrapper">
        <ul class="main-category-list has-children">
            <li>
                <a class="Parent_Mega_Menu_Categories MegaMenuLinkMainWithChildren" href="javascript:void(0)" style="">
                    Accessories
                </a>
                <ul class="secondary-items">
                    <li>
                        <a class="MegaMenu_Child_Link" href="https://www.google.com" style="">
                            Accessory Holders
                        </a>
                    </li>
                    <li>
                        <a class="MegaMenu_Child_Link" href="https://www.google.com" style="">
                            Whiteboard Starter Pack
                        </a>
                    </li>
                </ul>
            </li>
            <li>
                <a class="Parent_Mega_Menu_Categories MegaMenuLinkMainWithChildren" href="javascript:void(0)" style="">
                    Other
                </a>
                <ul class="secondary-items">
                    <li>
                        <a class="MegaMenu_Child_Link" href="https://www.google.com" style="">
                            Accessory
                        </a>
                    </li>
                    <li>
                        <a class="MegaMenu_Child_Link" href="https://www.google.com" style="">
                            Starter Pack
                        </a>
                    </li>
                </ul>
            </li>
        </ul>
    </div>
</div>
Lasithds
  • 2,161
  • 25
  • 39
  • 1
    Thanks for the cleaner code, I just found that Mouseleave causes the Sub-Menu to close right after when you tap the categories menu item on touch devices with Edge. – Tig7r Mar 23 '20 at 09:16
1

I have played around with some of the code and managed to get it to work. The mouseleave and hover event wont be fired on Touch Devices which makes it work.

$(document).ready(function () {

var touched = false;

    $(".item:contains(Categories)").on("mouseenter click", function (e) {
        if (!touched) {
            e.type == 'click' ? $('.MegaMenuDiv').toggleClass("displayHiddenMenu") : $('.MegaMenuDiv').addClass("displayHiddenMenu");
        }
    }).on('touchstart', function (e) {
        touched = true;
        setTimeout(function () {
            touched = false;
        }, 300);
        // do touchstart stuff (similar to click or not)
        // toggle MegaMenuDiv on click
        if ($('.MegaMenuDiv').hasClass('displayHiddenMenu')) {
            $('.MegaMenuDiv').removeClass("displayHiddenMenu");
        } else {
            $('.MegaMenuDiv').addClass("displayHiddenMenu");
        }
    });

    $('.MegaMenuDiv').on("mouseleave", function () {
        if (!touched) {
            $('.MegaMenuDiv').removeClass("displayHiddenMenu");
        }
    });

    // MegaMenuLinkMainWithChildren - Show children items
    $(".MegaMenuLinkMainWithChildren").on('mouseenter touchstart click', function () {
        // toggle MegaMenuDiv
        $('.MegaMenuLinkMainWithChildren').next().removeClass('displayHiddenMenu');
        $(this).next().addClass('displayHiddenMenu');
    });

    //Removes the sub-menu when hovering over other menu items
    $('.item').not(".item:contains(Categories)").hover(function () {
        console.log('Hovering over other items, remove class');
        if ($('.MegaMenuDiv').hasClass('displayHiddenMenu')) {
            $('.MegaMenuDiv').removeClass("displayHiddenMenu");
        }
    });

    //Add a cursor the the pointer
    $(".item:contains(Categories)").css("cursor", "pointer");

});

Here is the latest fiddle: https://jsfiddle.net/Tig7r/htLny8a7/1/

Tig7r
  • 525
  • 1
  • 4
  • 21