views:

46

answers:

2

When I hover over the parent links in my menu the class "toggle-active" is added to a span tag so the arrow image is changed. I also want this class to be added to the span tag when I'm hovering over the child links of the parent link inside the .sub-menu container, but I cannot get it to work. Here is the structure of the menu:

<ul>
<li>
<a href="#">Link 1 <span class="toggle-active"></span></a>
<ul class="sub-menu">
<li><a href="#">Sub link 1</a></li>
</ul>
</li>
</ul>

This is the jQuery I'm using:

 jQuery(".sub-menu").hide(); 

 jQuery("#gallery-nav").find("li").each(function() {

  if (jQuery(this).find("ul").length > 0) {

   jQuery("").appendTo(jQuery(this).children(":first"));

   jQuery("#gallery-nav li a").hover(function(){
    jQuery(this).children(".gallery-toggle-button").addClass("toggle-active");
    }, function () {
    jQuery(this).children(".gallery-toggle-button").removeClass("toggle-active");
   });

   jQuery("#gallery-nav li a").hover(function(){
    jQuery(this).next("ul").slideDown('fast');
   });

   jQuery("#gallery-nav li ul").hover(function(){
    jQuery(this).slideDown('fast');
    }, function () {
    jQuery(this).slideUp('fast');
   });

   jQuery("#gallery-nav li ul").hover(this).prev(function(){
    jQuery("#gallery-nav li a").children(".gallery-toggle-button").addClass("toggle-active");
    }, function () {
    jQuery("#gallery-nav li a").children(".gallery-toggle-button").removeClass("toggle-active");
   });

  }
+2  A: 

First of all, you might want to consider using :hover pseudoclass instead of jquery for this. For example, it's described here. It would clear all that javascript mess.

As for this particular issue, have you considered detecting hover on parent element li.menu-item? It includes each particular menu item (like 'abstract' and all its submenu elements ('design', 'blog' and 'full width page').
It could look like this

li.menu-item:hover {
    // some css to change arrow here
}

Or, if you need to select that particular span,

li.menu-item:hover span.gallery-toggle-button {
    background: url('your image path');
}

edit
Relevant piece of code from website:

<li class="menu-item menu-item-type-taxonomy menu-item-530" id="menu-item-530">
<a href="http://ghostpool.com/wordpress/phideo/?gallery_categories=abstract"&gt;Abstract
    <span class="gallery-toggle-button"></span>
</a>
<ul class="sub-menu" style="display: none;">
    <li class="menu-item menu-item-type-taxonomy menu-item-531" id="menu-item-531"><a href="http://ghostpool.com/wordpress/phideo/?gallery_categories=design"&gt;Design&lt;/a&gt;&lt;/li&gt;
    <li class="menu-item menu-item-type-post_type menu-item-537" id="menu-item-537"><a href="http://ghostpool.com/wordpress/phideo/?page_id=101"&gt;Blog&lt;/a&gt;&lt;/li&gt;
    <li class="menu-item menu-item-type-post_type menu-item-539" id="menu-item-539"><a href="http://ghostpool.com/wordpress/phideo/?page_id=40"&gt;Full Width Page</a></li>
</ul>
</li>
Nikita Rybak
Using CSS is a good idea. Nikita is right, you'd be able to write a lot less Javascript.
Dave Aaron Smith
The element I want to change on hover, "gallery-toggle-button" is not the child of menu-item links, it is simply next to it, so I don't see how I can use :hover in this case?
GhostPool
@ghostpool I was referring to code from your website (why did you delete the link, btw?) and there firebug clearly shows that _li.menu-item_ has two children: _a_ element for menu item itself (with _span.gallery-toggle-button_ inside) and _ul.sub-menu_ for all children elements. So, your statement isn't technically correct: _gallery-toggle-button_ is a descendant of _menu-item_
Nikita Rybak
@Nikita: I just thought it would be easier for me to paste the relevant code in my post instead of referring people to the site. I still can't see that if I hovered my mouse over one of the links within the `.sub-menu` how I could than change the background image of `.gallery-toggle-button` on hover. It is not a child of the link I want to hover over. Yes it would work if I hovered over the parent `.menu-item` link, but not a `.menu-iitem` link within .`sub-menu`. Do you not agree?
GhostPool
@ghostpool Note, that parent menu-item (you could create a separate class to distinguish it from child menu items) _includes_ both 'a' tag and child menu elements. And when you hover over child element, same hover even is triggered for all its parents (up to 'body' and 'html' elements).
Nikita Rybak
@ghostpool Here's a simple demonstration based on your code http://jsfiddle.net/mwKZw/
Nikita Rybak
@Nikita: You're completely right of course. I never knew you could do this in CSS, which is a bit embarrassing. Thanks very much. This will be very helpful for when JS is disabled especially.
GhostPool
A: 

I see a few problems.

.sub-menu

has that dash so it doesn't match this ul here

<ul class="submenu">

Next, Javascript closures are tricky. In this bit of code here, "this" stops meaning the "li" and starts meaning the element you matched on, which is the "a".

jQuery("#gallery-nav li a").hover(function(){
    jQuery(this).children(... // <- "this" now means "a", not "li"

In other words, you should do it this way

var top_li = this;
jQuery("#gallery-nav li a").hover(function(){
    jQuery(top_li).children(...

Finally, I'd just do the whole thing thusly.

<html>
  <head>
    <script type="text/javascript" src="http://www.google.com/jsapi"&gt;&lt;/script&gt;
    <script type="text/javascript">
      google.load("jquery", "1");
    </script>
    <script>
      $(function() {
        $(".sub-menu").hide();
        $("#gallery-nav li").each(function() {
          if ($(this).find("ul").length) {
            $(this).addClass("top_menu_li");
            $(this).find("a").eq(0).addClass("top_menu_a").append($("<span/>"));
          }
        });
        $(".top_menu_li").each(function() {
          var top_menu_li = $(this);
          top_menu_li.hover(function() {
            top_menu_li.find(".top_menu_a span").addClass("toggle-active");
            top_menu_li.find(".sub-menu").show();
          }, function() {
            top_menu_li.find(".top_menu_a").removeClass("toggle-active");
            top_menu_li.find(".sub-menu").hide();
          });
        });
      });
    </script>
  </head>
  <body>
    <ul id="gallery-nav">
      <li>
        <a href="#">Link 1</a>
        <ul class="sub-menu">
          <li><a href="#">Sub link 1</a></li>
        </ul>
      </li>
      <li>
        <a href="#">Link 2</a>
        <ul class="sub-menu">
          <li><a href="#">Sub link 2</a></li>
        </ul>
      </li>
    </ul>
  </body>
</html>

Edited

Now it adds the classes and spans. ghostpool, "find" targets children, so it only shows the correct sub navigation. Copy and paste that HTML and try it for yourself.

Dave Aaron Smith
There's nothing wrong with having dash in class name: I use them all the time, for both css and javascript manipulations.
Nikita Rybak
Nikita, I know. The dash itself isn't the problem. I just pointed out that ".sub-menu" has a dash while class="submenu" doesn't.
Dave Aaron Smith
Thanks Dave. That was just a typo, on the site itself the hyphen is present in both instances of sub-menu. Unfortunately this will not work, I'm using WordPress and the menu structure is auto generated, I have to use jQuery to insert the span tags for those list items with sub menus, I also need to use .children and .next to target only the current list item that is being hovered over, otherwise all list items show their sub menus.
GhostPool
@Dave Oh, sorry about that.
Nikita Rybak
ghostpool, try that. It works. Also it should reflect the html that wordpress generates.
Dave Aaron Smith
@Dave: This code works very well and I'll certainly be using it. Just one problem, the class 'toggle-active' is not removed after no longer hovering. I need this to happen so the arrow image goes back to what it was originally.
GhostPool
I've sorted it myself I believe, it should read `top_menu_li.find(".top_menu_a span").removeClass("toggle-active");` instead of `top_menu_li.find(".top_menu_a").removeClass("toggle-active");`
GhostPool