2

I have a menu structure where the Submenu that is hidden is not a child of the menu item. I have a span element inside the main top level link that will serve as an arrow to signify a submenu on mobile. When the user touches the span element I need the dropdown menu to have a class added (Javascript not using jQuery) in order to show it.

Something like this (Note that this is not how I would structure my menu, this is code already on a site that I cannot change)

<a href="#">Top Level Menu Item #1
<span>⇩</span>
</a>
<div class="dropdown-menu">Dropdown Menu Here</div>

<a href="#">Top Level Menu Item #2
<span>⇩</span>
</a>
<div class="dropdown-menu">Dropdown Menu Here</div>

<a href="#">Top Level Menu Item #3
<span>⇩</span>
</a>
<div class="dropdown-menu">Dropdown Menu Here</div>

So when span is touched or clicked, .dropdown-menu will have a class added to it.

4
  • Is your question answered? If so, pick the correct/best answer. If not, please comment what is missing/unclear.
    – connexo
    Commented Oct 22, 2018 at 15:22
  • I just posted this. Is there a time limit here or something? Why so pushy? Commented Oct 23, 2018 at 9:21
  • Sorry for appearing pushy. Many new contributors like you ask a question, but forget to ever pick an answer - and noone except the person asking the question can ever do that. So just take it as a reminder.
    – connexo
    Commented Oct 23, 2018 at 11:53
  • No worries. Thanks for taking the time to answer my question. Commented Oct 23, 2018 at 12:19

3 Answers 3

0

Just go with span.parentNode.nextElementSibling.classList.toggle('visible');

const spans = document.querySelectorAll('a>span');

for (const span of spans) {
  span.addEventListener('click', (e) => {
    e.stopPropagation();
    span.parentNode.nextElementSibling.classList.toggle('visible');
  })
}
.dropdown-menu {
  opacity: 0;
  transition: all .2s ease-in-out;
}

.dropdown-menu.visible {
  opacity: 1;
}
<a href="#">Top Level Menu Item #1
  <span>⇩</span>
</a>
<div class="dropdown-menu">Dropdown Menu Here</div>

<a href="#">Top Level Menu Item #2
  <span>⇩</span>
</a>
<div class="dropdown-menu">Dropdown Menu Here</div>

<a href="#">Top Level Menu Item #3
  <span>⇩</span>
</a>
<div class="dropdown-menu">Dropdown Menu Here</div>

Please note that I have limited the click listener to the <span>⇩</span> , the link itself is not affected.

Let me know if you need IE11-compatible code.

2
  • This answer works but since the span is within the <a> it always visits the link before the dropdown menu is shown. Seems this menu structure won't allow for this. Commented Oct 23, 2018 at 10:04
  • @houstonaspen That's what's being taken care of with e.stopPropagation(); which prevents bubbling of the click event from the inner span to the a parent.
    – connexo
    Commented Oct 23, 2018 at 11:52
0

You can just walk the dom, if that's the structure it will always have HTML wise with something like(providing you add a class to it, a wrapping class/id or something unique to the span):

const spans = Array.from(document.querySelectorAll('.dropdown-toggle'))

const addClassToSubmenu = el => {
  el.target.parentNode.nextElementSibling.classList.toggle('classtoadd')
}

spans.forEach(span => {
  span.addEventListener('click', addClassToSubmenu)
})

That'd do.

That's the snippet:

https://codepen.io/Venomzzz/pen/qJyvyN?editors=1010

8
  • So span does not have any classes or IDs. Would I select the 'a span' ? Commented Oct 22, 2018 at 14:26
  • Nope, because will select all the a spans in the whole document. You need to identify a way to target just those. Any chance you manage to share that specific structure of code so we can find out how to help you out better? Commented Oct 22, 2018 at 14:33
  • document.querySelectorAll('a span') will only select span elements which are descendants of a elements, not all spans on the page.
    – connexo
    Commented Oct 22, 2018 at 14:36
  • No reason to use external code sites. Instead, create a runnable snippet right within your answer.
    – connexo
    Commented Oct 22, 2018 at 14:36
  • So we are assuming here that the menu is the only part in the document that has a nested span inside a <a>? Which is what "document.querySelectorAll('a>span');" does.... Commented Oct 22, 2018 at 14:37
0

You could try accomplishing this with jQuery next():

Note: you need to add a "menu" class to your tags and you'd need to expand the mouseout and hover calls to keep your sub-menus from going away when you mouse out of the main menu.

CSS:

.dropdown-menu {display: none }

HTML:

<a href="#" class="menu">Top Level Menu Item #1
<span>⇩</span>
</a>
<div class="dropdown-menu">Dropdown Menu Here</div>
&nbsp;
<a href="#" class="menu">Top Level Menu Item #2
<span>⇩</span>
</a>
<div class="dropdown-menu">Dropdown Menu Here</div>
&nbsp;
<a href="#" class="menu">Top Level Menu Item #3
<span>⇩</span>
</a>
<div class="dropdown-menu">Dropdown Menu Here</div>    

JQuery:

$('.menu').hover(function() {
  $(this).next().css("display", "block");
});

$('.menu').mouseout(function() {
  $(this).next().css("display", "none");
});
2
  • In the question it states that I cannot use JQuery - Thanks anyway! Commented Oct 23, 2018 at 9:21
  • $.hover requires two functions to be passed to it. One for mouseenter, one for mouseleave.
    – connexo
    Commented Oct 23, 2018 at 12:14

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.