skip to Main Content

I’ve got a group of items that each have one or more data attributes (in an array). Above them, there’s a group of tabs each with a data attribute that is the same as it’s label. When I click a tab, I’d like to hide all the items that don’t have the same data attribute. This would be easy if each item had only one data attribute, but some have multiple and need to be shown if they match at all. I’m getting a little bogged down in the JS, but I feel like I’m close. Anyone see what I’m doing wrong?

Thank you

(function($) {
  $(document).ready(function() {

    $(".main .tabs .tab").click(function() {
      let currentTab;
      currentTab = $(this).data('dept');

      $(".main .tabs .tab").removeClass('active');
      $(this).addClass('active');

      // loop through all members and match those of currentTab
      $(".member-container .member").each(function(i, member) {

        if (currentTab == 'all') {
          $(member).removeClass('hide');
        } else {
          $(member).removeClass('hide');
          let memberDepts = $(member).data('dept');
          $(memberDepts).each(function(j, dept) {
            if ($(member).data('dept') != dept) {
              $(member).addClass('hide')
            }
          })
        }
      })
    })
  });
})(jQuery);
body {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.tabs {
  display: flex;
  column-gap: 15px;
  padding-top: 100px;
  justify-content: center;
}

.tabs .tab {
  padding: 20px;
  border: 2px solid green;
  cursor: pointer;
}

.tabs .tab.active {
  background-color: green;
  color: #fff;
}

.member-container {
  display: flex;
  width: 90%;
  padding-top: 100px;
  margin: 0 auto;
  flex-wrap: wrap;
  column-gap: 20px;
  row-gap: 20px;
}

.member-container .member {
  width: 30%;
  border: 2px solid red;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 25px;
}

.member-container .member.hide {
  display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<main class="main">
  <div class="tabs">
    <div data-dept="all" class="tab">All</div>
    <div data-dept="finance" class="tab">Finance</div>
    <div data-dept="adminisration" class="tab">Admin</div>
    <div data-dept="marketing" class="tab">Marketing</div>
    <div data-dept="executive" class="tab">Executive</div>
    <div data-dept="senior" class="tab">Senior</div>
    <div data-dept="organization" class="tab">Org</div>
  </div>

  <div class="member-container">
    <div data-dept="["finance"]" class="member">John Doe</div>
    <div data-dept="["finance", "marketing"]" class="member">Jane Doe</div>
    <div data-dept="["senior"]" class="member">Billy Bob</div>
    <div data-dept="["adminisration", "senior"]" class="member">Suzy Q</div>
    <div data-dept="["executive"]" class="member">Random Name</div>
    <div data-dept="["marketing"]" class="member">Another Name</div>
    <div data-dept="["organization","executive","marketing"]" class="member">Foo Bar</div>
    <div data-dept="["adminisration"]" class="member">Does it Matter?</div>
  </div>
</main>

I’ve got a link to codepen too : https://codepen.io/paul-molnar/pen/QWzazKq

4

Answers


  1. Try this out. Essentially your problem was around this code:

    let memberDepts = $(member).data('dept');
    $(memberDepts).each(function(j, dept) {
      if ($(member).data('dept') != dept) {
        $(member).addClass('hide')
      }
    })
    

    memberDepts is an array of strings, a list of the departments. You are then trying to select it as a jQuery object like it was an HTML element and loop over it. Within that loop you were trying to see if each member is contained or not.

    Since we already have the currently selected deparment as a string, and we have an array of strings, we can just use .includes() to greatly simplify this and correct the issue.

    if(!memberDepts.includes(currentTabDept)){
      thisMemberEl.addClass('hide')
    }
    

    I’ve also made a few other changes, mostly around selecting eleemnts as few times as possible. If you call $(member) 3 times in a loop of 10 items, that’s 30 calls to select elements! It only needs to happen once.

    (function ($) {
      $(function () {
        const allTabEls = $(".main .tabs .tab");
        const allMemberEls = $(".member-container .member");
        
        allTabEls.click(function () {
          const currentTabEl = $(this);
          const currentTabDept = currentTabEl.data('dept');
          
          //console.clear()
          //console.log('click', currentTabDept)
    
          allTabEls.removeClass('active');
          currentTabEl.addClass('active');
    
          // loop through all members and match those of currentTab
          allMemberEls
            .removeClass('hide')
            .each(function (i, member) {
              
              if (currentTabDept !== 'all') {
                const thisMemberEl = $(member);
                const memberDepts = thisMemberEl.data('dept');
                if(!memberDepts.includes(currentTabDept)){
                  //console.log('depts', memberDepts)
                  thisMemberEl.addClass('hide')
                }
              }
              
            });
        });
      });
    })(jQuery);
    body {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    
    .tabs {
        display: flex;
        column-gap: 15px;
        padding-top: 100px;
        justify-content: center;
    }
    
    .tabs .tab {
        padding: 20px;
        border: 2px solid green;
        cursor: pointer;
    }
    
    .tabs .tab.active {
        background-color: green;
        color: #fff;
    }
    
    .member-container {
        display: flex;
        width: 90%;
        padding-top: 100px;
        margin: 0 auto;
        flex-wrap: wrap;
        column-gap: 20px;
        row-gap: 20px;
    }
    
    .member-container .member {
        width: 30%;
        border: 2px solid red;
        height: 100px;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 25px;
    }
    
    .member-container .member.hide {
        display: none;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
    <main class="main">
        <div class="tabs">
            <div data-dept="all" class="tab">All</div>
            <div data-dept="finance" class="tab">Finance</div>
            <div data-dept="adminisration" class="tab">Admin</div>
            <div data-dept="marketing" class="tab">Marketing</div>
            <div data-dept="executive" class="tab">Executive</div>
            <div data-dept="senior" class="tab">Senior</div>
            <div data-dept="organization" class="tab">Org</div>
        </div>
    
        <div class="member-container">
            <div data-dept="[&#34;finance&#34;]" class="member">John Doe</div>
            <div data-dept="[&#34;finance&#34;, &#34;marketing&#34;]" class="member">Jane Doe</div>
            <div data-dept="[&#34;senior&#34;]" class="member">Billy Bob</div>
            <div data-dept="[&#34;adminisration&#34;, &#34;senior&#34;]" class="member">Suzy Q</div>
            <div data-dept="[&#34;executive&#34;]" class="member">Random Name</div>
            <div data-dept="[&#34;marketing&#34;]" class="member">Another Name</div>
            <div data-dept="[&#34;organization&#34;,&#34;executive&#34;,&#34;marketing&#34;]" class="member">Foo Bar</div>
            <div data-dept="[&#34;adminisration&#34;]" class="member">Does it Matter?</div>
        </div>
    </main>
    Login or Signup to reply.
  2. Use the array .includes() method to test if the selected tab is inside the array in the data attribute.

    (function($) {
      $(document).ready(function() {
        $(".main .tabs .tab").click(function() {
          let currentTab;
          currentTab = $(this).data('dept');
    
          $(".main .tabs .tab").removeClass('active');
          $(this).addClass('active');
    
          if (currentTab == 'all') {
            $(".member-container .member").removeClass('hide');
          } else {
            $(".member-container .member").each(function(i, member) {
              let memberDepts = $(member).data('dept');
              $(member).toggleClass('hide', !memberDepts.includes(currentTab));
            });
          }
        });
      });
    })(jQuery);
    body {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    
    .tabs {
      display: flex;
      column-gap: 15px;
      padding-top: 100px;
      justify-content: center;
    }
    
    .tabs .tab {
      padding: 20px;
      border: 2px solid green;
      cursor: pointer;
    }
    
    .tabs .tab.active {
      background-color: green;
      color: #fff;
    }
    
    .member-container {
      display: flex;
      width: 90%;
      padding-top: 100px;
      margin: 0 auto;
      flex-wrap: wrap;
      column-gap: 20px;
      row-gap: 20px;
    }
    
    .member-container .member {
      width: 30%;
      border: 2px solid red;
      height: 100px;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 25px;
    }
    
    .member-container .member.hide {
      display: none;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
    <main class="main">
      <div class="tabs">
        <div data-dept="all" class="tab">All</div>
        <div data-dept="finance" class="tab">Finance</div>
        <div data-dept="adminisration" class="tab">Admin</div>
        <div data-dept="marketing" class="tab">Marketing</div>
        <div data-dept="executive" class="tab">Executive</div>
        <div data-dept="senior" class="tab">Senior</div>
        <div data-dept="organization" class="tab">Org</div>
      </div>
    
      <div class="member-container">
        <div data-dept="[&#34;finance&#34;]" class="member">John Doe</div>
        <div data-dept="[&#34;finance&#34;, &#34;marketing&#34;]" class="member">Jane Doe</div>
        <div data-dept="[&#34;senior&#34;]" class="member">Billy Bob</div>
        <div data-dept="[&#34;adminisration&#34;, &#34;senior&#34;]" class="member">Suzy Q</div>
        <div data-dept="[&#34;executive&#34;]" class="member">Random Name</div>
        <div data-dept="[&#34;marketing&#34;]" class="member">Another Name</div>
        <div data-dept="[&#34;organization&#34;,&#34;executive&#34;,&#34;marketing&#34;]" class="member">Foo Bar</div>
        <div data-dept="[&#34;adminisration&#34;]" class="member">Does it Matter?</div>
      </div>
    </main>
    Login or Signup to reply.
  3. Try this. I just used spaces as delimiters between the depts. If you have dept. names with spaces, you could choose a different char as the delimiter or use a dash to represent a space.

    You can replace the .show() and .hide() with add/remove class. I just used those as a example.

    (function ($) {
        $(document).ready(function () {
    
            $(".main .tabs .tab").click(function () {
                let currentTab;
                currentTab = $(this).data('dept');
    
                $(".main .tabs .tab").removeClass('active');
                $(this).addClass('active');
    
                 if (currentTab == 'all') {
                        $('.member').show();
                 } else {
                        $('.member').each(function(i,member){
                          let depts = $(member).attr('data-dept').split(" ");
                          if (depts.includes(currentTab)) {
                            $(member).show();
                          } else {
                            $(member).hide();
                          }
                        });
                 }
            });
        });
    })(jQuery);
    body {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
    
    .tabs {
        display: flex;
        column-gap: 15px;
        padding-top: 100px;
        justify-content: center;
    }
    
    .tabs .tab {
        padding: 20px;
        border: 2px solid green;
        cursor: pointer;
    }
    
    .tabs .tab.active {
        background-color: green;
        color: #fff;
    }
    
    .member-container {
        display: flex;
        width: 90%;
        padding-top: 100px;
        margin: 0 auto;
        flex-wrap: wrap;
        column-gap: 20px;
        row-gap: 20px;
    }
    
    .member-container .member {
        width: 30%;
        border: 2px solid red;
        height: 100px;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 25px;
    }
    
    .member-container .member.hide {
        display: none;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
    <main class="main">
        <div class="tabs">
            <div data-dept="all" class="tab">All</div>
            <div data-dept="finance" class="tab">Finance</div>
            <div data-dept="adminisration" class="tab">Admin</div>
            <div data-dept="marketing" class="tab">Marketing</div>
            <div data-dept="executive" class="tab">Executive</div>
            <div data-dept="senior" class="tab">Senior</div>
            <div data-dept="organization" class="tab">Org</div>
        </div>
    
        <div class="member-container">
            <div data-dept="finance" class="member">John Doe</div>
            <div data-dept="finance marketing" class="member">Jane Doe</div>
            <div data-dept="senior" class="member">Billy Bob</div>
            <div data-dept="adminisration senior" class="member">Suzy Q</div>
            <div data-dept="executive" class="member">Random Name</div>
            <div data-dept="marketing" class="member">Another Name</div>
            <div data-dept="organization executive marketing" class="member">Foo Bar</div>
            <div data-dept="administration" class="member">Does it Matter?</div>
        </div>
    </main>
    Login or Signup to reply.
  4. Split your depts dataset by space, and use Array.prototype.includes()

    jQuery($ => {
    
      const $tabs = $(".main .tab");
      const $memb = $(".member-container .member");
      
      $tabs.on("click", function() {
        const dept = this.dataset.dept;
    
        $tabs.not(this).removeClass("active");
        $(this).addClass("active");
    
        $memb.each(function() {
          const show = dept === "all" || this.dataset.dept.split(/ /).includes(dept);
          $(this).toggleClass("hide", !show);
        });
      });
      
    });
    * {margin: 0; box-sizing: border-box; }
    
    .tabs {
      display: flex;
      gap: 0.5rem;
      justify-content: center;
    }
    
    .tabs .tab {
      padding: 1rem;
      border: 2px solid green;
      cursor: pointer;
    }
    
    .tabs .tab.active {
      background-color: green;
      color: #fff;
    }
    
    .member-container {
      display: flex;
      padding-top: 3rem;
      flex-wrap: wrap;
      gap: 1rem;
    }
    
    .member-container .member {
      width: 30%;
      border: 2px solid red;
      display: flex;
      padding: 1rem;
      align-items: center;
      justify-content: center;
    }
    
    .member-container .member.hide {
      display: none;
    }
    <main class="main">
      <div class="tabs">
        <div data-dept="all" class="tab active">All</div>
        <div data-dept="finance" class="tab">Finance</div>
        <div data-dept="adminisration" class="tab">Admin</div>
        <div data-dept="marketing" class="tab">Marketing</div>
        <div data-dept="executive" class="tab">Executive</div>
        <div data-dept="senior" class="tab">Senior</div>
        <div data-dept="organization" class="tab">Org</div>
      </div>
    
      <div class="member-container">
        <div data-dept="finance" class="member">John Doe</div>
        <div data-dept="finance marketing" class="member">Jane Doe</div>
        <div data-dept="senior" class="member">Billy Bob</div>
        <div data-dept="adminisration senior" class="member">Suzy Q</div>
        <div data-dept="executive" class="member">Random Name</div>
        <div data-dept="marketing" class="member">Another Name</div>
        <div data-dept="organization executive marketing" class="member">Foo Bar</div>
        <div data-dept="adminisration" class="member">Does it Matter?</div>
      </div>
    </main>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search