paul blackmore
paul blackmore

Reputation: 331

Can not target class after addClass

I have an icon that when clicked adds a class to the nav-btn class and the menu animates to the full height of screen.

$('.nav-btn').click(function(){
        $(this).toggleClass('open');
        $('nav').animate({height: '100vh'});    
    });

When I try and close the menu by calling both the original and added class, it is unresponsive.

$('.nav-btn.open').click(function(){
        console.log('test');
        $('nav').animate({height: '60px'});
    });

I can't even see the console.log in the console so I'm thinking that I'm not calling the class correctly but I have tried a few combinations and nothing works and from reading other peoples issues I'm calling the call correctly. Please help!

Upvotes: 0

Views: 162

Answers (3)

Tank
Tank

Reputation: 1006

As an alternative solution - If the goal is only the open/close animation, the same result can be achieved with a CSS transition. This way you will only have to worry about toggling the .open class on and off.

$('.nav-btn').on('click', function(){
   $('nav').toggleClass('open');   
});
nav {
  border:.1em solid blue;
  height:1em;
  transition:height 300ms;
}

nav.open {
  height:80vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<a class="nav-btn" href="#">Navigation</a>
<nav></nav>

Upvotes: 0

Rich
Rich

Reputation: 1635

@Terry's response works just fine as well, but something else you can keep in mind is a concept called event delegation. As Terry explained, the problem you are experiencing is being caused because you are attaching an event handler to an element that doesn't yet exist.

However, with Event Delegation, you can attach the event to a parent element that you know will always be there (either the document, or just some container element). Using $.on(...), you attach the handler to the parent element, and the event bubbles down to the specified element, regardless of whether it exists in the DOM yet or not.

Below, I modified your sample to show how event delegation works. (I think Terry's response is cleaner, but delegation is a helpful subject to understand).

$("#btn-parent")
  .on("click", ".nav-btn.close", function() {
    $(this).toggleClass('open').toggleClass("close");
    $('nav').animate({height: '100vh'});
  })
  .on("click", ".nav-btn.open", function() {
    $(this).toggleClass('open').toggleClass("close");
    $('nav').animate({height: '20px'});
  });
nav {
  background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="btn-parent">
  <button class="nav-btn close">Nav Button</button>
</div>

<nav>Navigation</nav>

Upvotes: 0

Terry
Terry

Reputation: 66173

That is because you are binding the click event to the .nav-btn.open at runtime, which does not exist yet (the class is only added when the user clicks the button). Instead of binding two separate events, you can combine the logic into your first click handler, and simply add a conditional check if the class open is present on the button:

$('.nav-btn').click(function(){
  var $t = $(this);
  var $n = $('nav');

  if (!$t.hasClass('open'))
    $n.animate({height: '100vh'});
  else
    $n.animate({height: '60px'});    

  $t.toggleClass('open');
});
nav {
  background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<button class="nav-btn">Nav Button</button>
<nav>Navigation</nav>

Even better: you can give store the target height value in a variable and use ternary operators to assign the desired value:

$('.nav-btn').click(function() {
  var $t = $(this);
  var targetHeight = $t.hasClass('open') ? '60px' : '100vh';

  $('nav').animate({ height: targetHeight });
  $t.toggleClass('open');
});
nav {
  background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<button class="nav-btn">Nav Button</button>
<nav>Navigation</nav>

Upvotes: 2

Related Questions