Brecherchef
Brecherchef

Reputation: 397

jQuery each run function on every other element

I'm working on a basic dropdown element in HTML and jQuery and I'm trying to get better at understanding JavaScript and jQuery so this questions is a bit about code refactoring as well.

So here is what I've gotten so far:

HTML

<li class="nav-item">
    <a class="nav-link" href="#">Foo</a>
    <div class="subnav">
       ...
    </div>
</li>

JavaScript

const navLink = $('.nav-link');

navLink.each(function () {
    let $this = $(this);
    $this.click(function (e) {
        let hasSubnav = $this.parent().find('.subnav');
        if(hasSubnav.length !== 0) {
            e.preventDefault();
            $this.toggleClass('dropdown-active');
        }
        hasSubnav.stop(true, true).slideToggle(200);
    })
});

This solutions works fine. So what I want to do next is to check if another element in my loop is active, close is accordingly and then open the one I just clicked.

I thought about just putting a default click function before the each function like this:

navLink.click(function () {
    $('.subnav').slideUp();
});
navLink.each(function () {
    let $this = $(this);
    $this.click(function (e) {
        let hasSubnav = $this.parent().find('.subnav');
        if(hasSubnav.length !== 0) {
            e.preventDefault();
            $this.toggleClass('dropdown-active');
        }
        hasSubnav.stop(true, true).slideDown(200);
    })
});

But this does not seem to work. So my question is, is there a pretty way to achieve this maybe even inside of the each function? I've red about .not(this) in this post, which will maybe work (haven't tried it yet) but I thought that this would be duplicated code and that there might be a better way to get this to work.

Upvotes: 1

Views: 264

Answers (1)

etarhan
etarhan

Reputation: 4176

Your code is now looping through every single nav-link and adding a click handler to them one by one. It is possible to remove the each loop, since you can just add a click handler to all nav-links at once.

All you have to do is add a click handler to the nav-link and then remove the active class and slide up all open dropdowns before executing your logic. See working code example below for reference:

// Collapse all initially
$(".subnav").slideUp();

// Add click handler to all nav-links
const navLink = $('.nav-link');
navLink.click(function(e) {
  // Remove active classes on other elements & slide up
  const otherLinks = navLink.not(this);
  otherLinks.removeClass('dropdown-active');
  otherLinks.parent().find('.subnav').slideUp();
  
  // Slide down the subnav of selected element
  let hasSubnav = $(this).parent().find('.subnav');
  if (hasSubnav.length !== 0) {
    e.preventDefault();
    $(this).addClass('dropdown-active');
  }
  hasSubnav.stop(true, true).slideToggle(200);
})
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>

<li class="nav-item">
  <a class="nav-link" href="#">Foo</a>
  <div class="subnav">
    <a href="#">Link1</a>
    <a href="#">Link2</a>
    <a href="#">Link3</a>
  </div>
</li>
<li class="nav-item">
  <a class="nav-link" href="#">Foo</a>
  <div class="subnav">
    <a href="#">Link1</a>
    <a href="#">Link2</a>
    <a href="#">Link3</a>
  </div>
</li>

Upvotes: 2

Related Questions