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

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.


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


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');
    }
  });
}