Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bootstrap Avoid navbar-toggle button to close opened sub menus on mobile

I have a code based on Bootstrap 3.3.7
There are different menu items and sub menus on my menu, I want to have all sub menu items to be open on mobile, Means no need to click on any menu items to display it's sub menus, So I wrote a JS code to open all sub menus on mobile:

function opensubmenus() {
  if ($(window).width() < 768) {
    $("#top-navbar-collapse li").addClass('open');
  } else {
    $("#top-navbar-collapse li").removeClass('open');
  }
}

$(window).resize(opensubmenus);
opensubmenus();

But the problem is when I click on a navbar-toggle button, It closes all submenus, But I need to keep them open on mobile devices all the time You can check my online sample on this site: https://dedidata.com

Here I have shown a screenshot: https://pasteboard.co/IfSMCIu.jpg

I don't like to disable navbar-toggle button completely, I need it to toggle the whole navbar, But I don't like it close the submenus, My JS code opens the submenus, But navbar-toggle closes those submenus

like image 720
Farhad Sakhaei Avatar asked May 19 '19 14:05

Farhad Sakhaei


3 Answers

This snippet will be applied to all dropdowns, you can modify it to get what dropdowns you need.

I will explain what it does:

const targets = document.getElementsByClassName('dropdown-toggle');

for(let i = 0; i < targets.length; i++) {
  targets[i].addEventListener('click', () => {
    targets[i].hasAttribute('data-toggle') &&
      targets[i].removeAttribute('data-toggle');

    // Managing locally the open and close
    targets[i].parentElement.classList.toggle('open');    
  });
}

First line:

const targets = document.getElementsByClassName('dropdown-toggle');

we get all the elements with class name dropdown-toggle (this is used in boostrap for dropdowns menus)

For each element, we attach a click listener to be able to manage "manually" dropdowns if the dropdown menu is clicked by the user.

This is managed by line: targets[i].parentElement.classList.toggle('open');

And the important one to avoid auto closing menus is to remove the attribute data-toggle.

targets[i].hasAttribute('data-toggle') &&
          targets[i].removeAttribute('data-toggle');

If you only one apply a solution like this for mobiles you can use is.js to check when you are in mobile (android/ios)

UPDATE

This update will open the menus automatically:

const menuItems = document.getElementsByClassName('navbar-toggle');

for (let i = 0; i < menuItems.length; i++) {
  menuItems[i].hasAttribute('data-toggle') && menuItems[i].addEventListener('click', () => {    
    const elements = document.getElementsByClassName('dropdown-toggle');
    for (let i = 0; i < elements.length; i++) {
      elements[i].hasAttribute('data-toggle') && elements[i].removeAttribute('data-toggle');      
      elements[i].parentElement.classList.add('open');
    }
  });
}
like image 175
F.bernal Avatar answered Oct 20 '22 09:10

F.bernal


The following code expands the sub menus when a click occurs on navbar-toggle and it change the aria-expanded to the correct value based on the open/close state of sub menu

function opensubmenus() {
    if ($(window).width() < 768) {
        $("#top-navbar-collapse li").addClass('open');
        $("#top-navbar-collapse li a").attr('aria-expanded','true');
    }else{
        $("#top-navbar-collapse li").removeClass('open');
        $("#top-navbar-collapse li a").attr('aria-expanded','false');
    }
}

$('#top-menu .navbar-toggle').click(function(){
    setTimeout(opensubmenus, 100);
});

$(window).resize(opensubmenus);
opensubmenus();

Thanks to @abelito for his hint

like image 25
Farhad Sakhaei Avatar answered Oct 20 '22 10:10

Farhad Sakhaei


Straight code after tinkering for 10 minutes. I definitely don't recommend this as a final answer, but this will get you on the track towards one way of accomplishing it:

function delayedSubmenuOpen() { setTimeout(openAllSubmenus, 100); }

function openAllSubmenus() {
    var eles = document.getElementsByClassName("dropdown-toggle");
    for (i = 0; i < eles.length; i++) { 
        eles.item(i).parentElement.className += " open";
    }
}

var navigationHamburger = document.getElementsByClassName("navbar-toggle").item(0);
navigationHamburger.addEventListener("click", delayedSubmenuOpen);

I would definitely replace all of these with cross-browser compliant jQuery calls, as I did it in straight javascript and only tested in my browser on Chrome.

I'd also look into just editing the CSS instead rather than relying on javascript to do this -- maybe on page load, make a renamed copy of the ".open" class and add it to all elements with the classname "menu-item-has-children" -- this way it can't be toggled off by the javascript. Sounds like you may have tried this but definitely worth looking into rather than depending on some hokey JS.

like image 3
abelito Avatar answered Oct 20 '22 10:10

abelito