Rafael
Rafael

Reputation: 1487

Dropdown submenu not recognizing click

I've got this menu that if the page width can't hold all of its items those remaining items are added to a more option.

The thing is, I can't open links when I click on a submenu from the more option. Here's an example which logs the link when clicked.

$(".top_menu li").click(function() {

  console.log($(this).data('link'));

  // Checks if there is a link
  if (typeof $(this).data('link') !== 'undefined') {
    //document.location.href = $(this).data('link');
  }
});
$(".top_menu ul").each(function() {
  alignMenu(this);
  var robj = this;
  $(window).resize(function() {
    $(robj).append($($($(robj).children("li.hideshow")).children("ul")).html());
    $(robj).children("li.hideshow").remove();
    alignMenu(robj);
  });

  function alignMenu(obj) {
    var w = 0;
    var mw = $(obj).width() - 150;
    var i = -1;
    var menuhtml = '';
    jQuery.each($(obj).children(), function() {
      i++;
      w += $(this).outerWidth(true);
      if (mw < w) {
        menuhtml += $('<div>').append($(this).clone()).html();
        $(this).remove();
      }
    });
    $(obj).append('<li class="hideshow">MORE&nbsp;&nbsp;<i class="material-icons">keyboard_arrow_down</i><ul>' + menuhtml + '</ul></li>');
    $(obj).children("li.hideshow ul").css("top", $(obj).children("li.hideshow").outerHeight(true) + "px");

    // Opens the menu
    $(obj).children(".hideshow").click(function() {
      $(this).find("ul").animate({
        height: 'toggle'
      }, 'fast');
    });
  }
});
.top_menu {
  width: 100%;
}

ul.horizontal-menu,
.horizontal-menu ul {
  list-style-type: none;
  margin: 0;
  padding: 0;
}

.horizontal-menu {
  float: left;
  width: 100%;
  background: #616161;
}

.horizontal-menu li {
  float: left;
  display: block;
  padding: 25px;
  color: #FFFFFF;
  text-decoration: none;
  -webkit-transition: border-color .218s;
  -moz-transition: border .218s;
  -o-transition: border-color .218s;
  transition: border-color .218s;
  background: #616161;
  cursor: pointer;
}

.horizontal-menu li .material-icons {
  margin: -10px;
}

.hideshow ul li {
  width: 250px;
  text-align: center;
}

.horizontal-menu li:hover {
  border-bottom: 3px solid rgb(246, 83, 20);
  padding-bottom: 22px;
  background: #484848;
}

.horizontal-menu li.hideshow ul {
  position: absolute;
  display: none;
  left: -203px;
  width: 300px;
}

.horizontal-menu li.hideshow {
  position: relative;
}

.hideshow ul {
  padding-bottom: 7px;
  background: #616161;
  border-radius: 0px 0px 4px 4px;
  margin-top: 25px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- Material Icons (Google) -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<div class="top_menu">
  <ul class="horizontal-menu">
    <li>&nbsp;<i class="material-icons">search</i>&nbsp;</li>
    <li data-link="http://www.google.com">MENU 1</li>
    <li data-link="http://www.google.com">MENU 2</li>
    <li data-link="http://www.google.com">MENU 3</li>
    <li data-link="http://www.google.com">MENU 4</li>
    <li data-link="http://www.google.com">MENU 5</li>
    <li data-link="http://www.google.com">MENU 6</li>
    <li data-link="http://www.google.com">MENU 7</li>
    <li data-link="http://www.google.com">MENU 8</li>
    <li data-link="http://www.google.com">MENU 9</li>
    <li data-link="http://www.google.com">MENU 10</li>
    <li data-link="http://www.google.com">MENU 11</li>
    <li data-link="http://www.google.com">MENU 12</li>
    <li data-link="http://www.google.com">MENU 13</li>
    <li data-link="http://www.google.com">MENU 14</li>
  </ul>
</div>

Upvotes: 1

Views: 99

Answers (3)

Nadir Laskar
Nadir Laskar

Reputation: 4150

You need to do event delegation as your li's are getting added dynamically

$(".top_menu li").click(function() {...

The above code will add event listener to li directly which will cause problem as you are rearranging the li in the DOM dynamically.

You have to use event delegation.

$(".top_menu").on('click','li[data-link]',function() {...

This code will add event listener to top-menu but delegate the event to all its decedent li with selector li[data-link]

Read about Event Delegation

Event delegation allows us to attach a single event listener, to a parent element, that will fire for all descendants matching a selector, whether those descendants exist now or are added in the future.

Check out my this answer for explanation on event delegation .

SNIPPET

$(".top_menu").on('click','li[data-link]',function() {

  console.log($(this).data('link'));

  // Checks if there is a link
  if (typeof $(this).data('link') !== 'undefined') {
    //document.location.href = $(this).data('link');
  }
});
$(".top_menu ul").each(function() {
  alignMenu(this);
  var robj = this;
  $(window).resize(function() {
    $(robj).append($($($(robj).children("li.hideshow")).children("ul")).html());
    $(robj).children("li.hideshow").remove();
    alignMenu(robj);
  });

  function alignMenu(obj) {
    var w = 0;
    var mw = $(obj).width() - 150;
    var i = -1;
    var menuhtml = '';
    jQuery.each($(obj).children(), function() {
      i++;
      w += $(this).outerWidth(true);
      if (mw < w) {
        menuhtml += $('<div>').append($(this).clone()).html();
        $(this).remove();
      }
    });
    $(obj).append('<li class="hideshow">MORE&nbsp;&nbsp;<i class="material-icons">keyboard_arrow_down</i><ul>' + menuhtml + '</ul></li>');
    $(obj).children("li.hideshow ul").css("top", $(obj).children("li.hideshow").outerHeight(true) + "px");

    // Opens the menu
    $(obj).children(".hideshow").click(function() {
      $(this).find("ul").animate({
        height: 'toggle'
      }, 'fast');
    });
  }
});
.top_menu {
  width: 100%;
}

ul.horizontal-menu,
.horizontal-menu ul {
  list-style-type: none;
  margin: 0;
  padding: 0;
}

.horizontal-menu {
  float: left;
  width: 100%;
  background: #616161;
}

.horizontal-menu li {
  float: left;
  display: block;
  padding: 25px;
  color: #FFFFFF;
  text-decoration: none;
  -webkit-transition: border-color .218s;
  -moz-transition: border .218s;
  -o-transition: border-color .218s;
  transition: border-color .218s;
  background: #616161;
  cursor: pointer;
}

.horizontal-menu li .material-icons {
  margin: -10px;
}

.hideshow ul li {
  width: 250px;
  text-align: center;
}

.horizontal-menu li:hover {
  border-bottom: 3px solid rgb(246, 83, 20);
  padding-bottom: 22px;
  background: #484848;
}

.horizontal-menu li.hideshow ul {
  position: absolute;
  display: none;
  left: -203px;
  width: 300px;
}

.horizontal-menu li.hideshow {
  position: relative;
}

.hideshow ul {
  padding-bottom: 7px;
  background: #616161;
  border-radius: 0px 0px 4px 4px;
  margin-top: 25px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- Material Icons (Google) -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<div class="top_menu">
  <ul class="horizontal-menu">
    <li>&nbsp;<i class="material-icons">search</i>&nbsp;</li>
    <li data-link="http://www.google.com">MENU 1</li>
    <li data-link="http://www.google.com">MENU 2</li>
    <li data-link="http://www.google.com">MENU 3</li>
    <li data-link="http://www.google.com">MENU 4</li>
    <li data-link="http://www.google.com">MENU 5</li>
    <li data-link="http://www.google.com">MENU 6</li>
    <li data-link="http://www.google.com">MENU 7</li>
    <li data-link="http://www.google.com">MENU 8</li>
    <li data-link="http://www.google.com">MENU 9</li>
    <li data-link="http://www.google.com">MENU 10</li>
    <li data-link="http://www.google.com">MENU 11</li>
    <li data-link="http://www.google.com">MENU 12</li>
    <li data-link="http://www.google.com">MENU 13</li>
    <li data-link="http://www.google.com">MENU 14</li>
  </ul>
</div>

Upvotes: 3

RLHawk
RLHawk

Reputation: 476

The issue is that the $(".top_menu li").click(...) function only applies to the li elements that exist at that time, and your code is removing and reattaching them to the dom later on. In order to attach to any li elements with a link that exist at that time or later, you can use the .on('click', selector, ...). And to avoid including the li.hideshow element you can use li[data-link] as the selector.

$(".top_menu").on('click', 'li[data-link]', function() {

  console.log($(this).data('link'));

  // Checks if there is a link
  if (typeof $(this).data('link') !== 'undefined') {
    //document.location.href = $(this).data('link');
  }
});
$(".top_menu ul").each(function() {
  alignMenu(this);
  var robj = this;
  $(window).resize(function() {
    $(robj).append($($($(robj).children("li.hideshow")).children("ul")).html());
    $(robj).children("li.hideshow").remove();
    alignMenu(robj);
  });

  function alignMenu(obj) {
    var w = 0;
    var mw = $(obj).width() - 150;
    var i = -1;
    var menuhtml = '';
    jQuery.each($(obj).children(), function() {
      i++;
      w += $(this).outerWidth(true);
      if (mw < w) {
        menuhtml += $('<div>').append($(this).clone()).html();
        $(this).remove();
      }
    });
    $(obj).append('<li class="hideshow">MORE&nbsp;&nbsp;<i class="material-icons">keyboard_arrow_down</i><ul>' + menuhtml + '</ul></li>');
    $(obj).children("li.hideshow ul").css("top", $(obj).children("li.hideshow").outerHeight(true) + "px");

    // Opens the menu
    $(obj).children(".hideshow").click(function() {
      $(this).find("ul").animate({
        height: 'toggle'
      }, 'fast');
    });
  }
});
.top_menu {
  width: 100%;
}

ul.horizontal-menu,
.horizontal-menu ul {
  list-style-type: none;
  margin: 0;
  padding: 0;
}

.horizontal-menu {
  float: left;
  width: 100%;
  background: #616161;
}

.horizontal-menu li {
  float: left;
  display: block;
  padding: 25px;
  color: #FFFFFF;
  text-decoration: none;
  -webkit-transition: border-color .218s;
  -moz-transition: border .218s;
  -o-transition: border-color .218s;
  transition: border-color .218s;
  background: #616161;
  cursor: pointer;
}

.horizontal-menu li .material-icons {
  margin: -10px;
}

.hideshow ul li {
  width: 250px;
  text-align: center;
}

.horizontal-menu li:hover {
  border-bottom: 3px solid rgb(246, 83, 20);
  padding-bottom: 22px;
  background: #484848;
}

.horizontal-menu li.hideshow ul {
  position: absolute;
  display: none;
  left: -203px;
  width: 300px;
}

.horizontal-menu li.hideshow {
  position: relative;
}

.hideshow ul {
  padding-bottom: 7px;
  background: #616161;
  border-radius: 0px 0px 4px 4px;
  margin-top: 25px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- Material Icons (Google) -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<div class="top_menu">
  <ul class="horizontal-menu">
    <li>&nbsp;<i class="material-icons">search</i>&nbsp;</li>
    <li data-link="http://www.google.com">MENU 1</li>
    <li data-link="http://www.google.com">MENU 2</li>
    <li data-link="http://www.google.com">MENU 3</li>
    <li data-link="http://www.google.com">MENU 4</li>
    <li data-link="http://www.google.com">MENU 5</li>
    <li data-link="http://www.google.com">MENU 6</li>
    <li data-link="http://www.google.com">MENU 7</li>
    <li data-link="http://www.google.com">MENU 8</li>
    <li data-link="http://www.google.com">MENU 9</li>
    <li data-link="http://www.google.com">MENU 10</li>
    <li data-link="http://www.google.com">MENU 11</li>
    <li data-link="http://www.google.com">MENU 12</li>
    <li data-link="http://www.google.com">MENU 13</li>
    <li data-link="http://www.google.com">MENU 14</li>
  </ul>
</div>

Upvotes: 0

Gerard
Gerard

Reputation: 15786

Your event trigger is not correct. You can change it into the below or add a class to the other ul.

$("li").click(function() {

Upvotes: -1

Related Questions