2

I have a pretty simple setup:

  • button: toggles “toggled” class on the nav
  • li is simplified holder for submenu: it should change aria attribute on click, but only when the nav has .toggled class on it

But for some reason this line doesn't work:

$('.toggled .has-children').on('click', function(e){

Is it because the class is added dynamically to the parent? How would I overcome this?

$(function() {
  

  var container = $('.nav');
  var button = $('.menu');
  
  //add remove class to nav
  button.on('click', function () {
      if(container.hasClass('toggled')) {
          container.removeClass('toggled');
      } else {
          container.addClass('toggled');
      }
  });

  // doesn't work?
  $('.toggled .has-children').on('click', function(e){
    e.preventDefault();
    $(this).attr('aria-expanded', 'true');
  })
  
});
.toggled {
  color: blue;
}

.has-children[aria-expanded=true] {
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<nav class="nav"> 
<button class="menu">Menu</button>

  <ul>
    <li class="has-children" aria-expanded="false">
      Has children
    </li>  
    
  </ul>
  
</nav>
kukkuz
  • 41,512
  • 6
  • 59
  • 95
Runnick
  • 613
  • 2
  • 12
  • 30

2 Answers2

3

If would suffice to make the click listener a dynamic listener like this based on a static element like body:

$('body').on('click', '.toggled .has-children', function(e){

See working demo below:

$(function() {
  var container = $('.nav');
  var button = $('.menu');
  //add remove class to nav
  button.on('click', function() {
    if (container.hasClass('toggled')) {
      container.removeClass('toggled');
    } else {
      container.addClass('toggled');
    }
  });

  $('body').on('click', '.toggled .has-children', function(e) {
    e.preventDefault();
    $(this).attr('aria-expanded', 'true');
  })
});
.toggled {
  color: blue;
}
.has-children[aria-expanded=true] {
  color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav class="nav">
  <button class="menu">Menu</button>
  <ul>
    <li class="has-children" aria-expanded="false">
      Has children
    </li>
  </ul>
</nav>
kukkuz
  • 41,512
  • 6
  • 59
  • 95
  • If you have a non-small application is this still efficient? –  Aug 19 '17 at 16:13
  • yup, if you see anything *dyanmic*, then listeners need to be *binded* this way... but I would prefer using something like `angularjs` for the big-stage... – kukkuz Aug 19 '17 at 16:16
  • 1
    neat trick, didn't know about this one. –  Aug 19 '17 at 16:17
1

This is not working because you bind the click event before adding the toggled class.

You should only bind the click after the toggle has been added:

$(function() {


  var container = $('.nav');
  var button = $('.menu');

  var addExpanded = function(){
    $('.toggled .has-children').unbind().on('click', function(e){
      e.preventDefault();
      $(this).attr('aria-expanded', 'true');
    })
  }

  //add remove class to nav
  button.on('click', function () {
      if(container.hasClass('toggled')) {
          container.removeClass('toggled');
      } else {
          container.addClass('toggled');
          addExpanded()    
      }
  });  
});