7

I have some simple JS that removes or adds html based on the width of the browser. If it's in mobile then the attribute data-hover should be removed. If the width is in desktop, then the attribute should be added.

So far this works great, but the problem is Bootstrap doesn't recognize that data-hover has been removed. The dropdown still closes when the user's mouse leaves the dropdown. To be clear, I want the dropdown to stay open when the user's mouse leaves the dropdown when the window browser width's is below 768px.

What's wrong and how do I fix this?

JS

$(document).ready(function () {
  $( window ).resize(function() {
    if ($( window ).width() < 768) {
      $('.dropdown-toggle').removeAttr('data-hover');
    } else {
      $('.dropdown-toggle').attr('data-hover', 'dropdown');
    }
  });
});

HTML

<a class="dropdown-toggle" data-hover="dropdown" data-toggle="dropdown" role="menu" aria-expanded="false" href="/courses">
  Courses               
</a>

<ul class="dropdown-menu courses-dropdown">
  <li>hello</li>                            
</ul>
thank_you
  • 11,001
  • 19
  • 101
  • 185

3 Answers3

4

Instead of removing the attribute completely, you could reassign it to nothing like so:

$('.dropdown-toggle').attr('data-hover', '');

If there is no value assigned to the attribute, it shouldn't do anything.

BDD
  • 665
  • 17
  • 31
1

NOTE: The solution provided by BDD with regards to setting data-hover to an empty string will work if you are using the responsibly built dropdown hover plugin. However, the OP was using a rather poorly built dropdown hover plugin and this answer serves to duct tape the problems with that plugin.

It appears that the data-hover is not part of bootstraps dropdown but rather some guys extension to bootstrap. Unfortunate for you and the community at large the guy didn't provide a way to destroy his plugin. It always amazes me how plugin authors never provide a way to tear down their plugins as this is a severe cause of memory leaks and is is just poor programming in general.</rant>

In order to make things right, you are going to have to manually unbind and rebind the events yourself. Again, unfortunate for you and the community, he didn't namespace the hover events - which, again, is real irresponsible plugin development (crying inside). Since we are going to be doing all this work that the plugin author should have done, we might as well extend the plugin and make it appear as though the author knew what he was doing. Please note that if any other functionality on the page is adding hover events to the dropdowns, that functionality is going to break (this is because the author didn't namespace his events).

$.fn.dropdownHover.disableAll = function () {
    $('[data-hover="dropdown"]').each(function() {
        $(this).off('hover').parent().off('hover').find('.dropdown-submenu').off('hover');
    });
});

$.fn.dropdownHover.enableAll = function () {
    $('[data-hover="dropdown"]').dropdownHover();
});

and now inside your resize event you should do something like this:

var $window = $( window );
$(document).ready(function () {
  $window.resize(function() {
    if ($window.width() < 768) {
      $.fn.dropdownHover.disableAll();
    } else {
      $.fn.dropdownHover.enableAll();
    }
  });
});

You may have to play around with the above code since I can't really test this. Let me know if it works or not. And since we've gone to all this work, for the love of everything good in this world will you please call the disableAll function if you are using this on a single page application and the current page changes. This is how you can prevent memory leaks. Thanks.

Ryan Wheale
  • 26,022
  • 8
  • 76
  • 96
  • Excellent write up. I'm going to test this out. Although the original answer worked for me I'm starting to have some slight issues with it. Let me test your answer out and see what happens. – thank_you Jun 23 '16 at 18:00
  • It appears there are multiple plugins that use the same technique, so I might have picked the wrong plugin. Can you tell me which `data-hover` plugin you are using - it's not part of bootstrap core. [This one](http://kybarg.github.io/bootstrap-dropdown-hover/) actually did it correctly, and they are already disabling it on window resize below 768 so you shouldn't need to write any code to turn it off or on. – Ryan Wheale Jun 23 '16 at 18:15
  • Did some digging and I'm using this. https://github.com/CWSpear/bootstrap-hover-dropdown – thank_you Jun 23 '16 at 18:53
  • Yup, that's the one I referenced in my answer. I'm not sure how the other solution worked for you. I recommend switching to [this one](http://kybarg.github.io/bootstrap-dropdown-hover/) if you can, otherwise try the code from my answer above. Like I said you might have to adjust the code above a little since I couldn't really test it - but you should be able to see what's happening. – Ryan Wheale Jun 23 '16 at 19:31
  • Thanks Ryan! Will do. – thank_you Jun 23 '16 at 20:46
0

Do this for the drop down menu to show on hover on the desktop and on click for mobile:

Take the dropdown menu above with data-toggle="dropdown":

<a class="dropdown-toggle" data-toggle="dropdown" role="menu" aria-expanded="false" href="www.example.com">
  Parent
</a>
<ul class="dropdown-menu">
  <li>Child 1</li>                            
  <li>Child 2</li>          
  <li>Child 3</li>                            
</ul>

data-toggle="dropdown" will prevent redirecting to URL on click and on touch.

Use ontouchstart to detect mobile browser, and then force redirecting to URL when click on parent item only for desktop (NOT mobile):

function is_touch_device() {
  return !!('ontouchstart' in window);
}
$(document).ready(function() {
    if(!is_touch_device()) {
        $('a.dropdown-toggle[data-toggle="dropdown"]').click(function (e) {
            window.location.href = $(this).attr('href');
        });
    }
});
cawecoy
  • 2,359
  • 4
  • 27
  • 36