0

I have a filtering button system for my gallery (as seen in the code below), but how do I add another button filter above this current sub filter.

Example:
1st filtering level: Beginner | Mid | Advanced
2nd filtering level: Upper-body | Lower-body | Core | Stretch (code for this level is done as seen below)

My code:

filterSelection("all")

function filterSelection(c) {
  var x, i;
  x = document.getElementsByClassName("column");
  if (c == "all") c = "";
  for (i = 0; i < x.length; i++) {
    w3RemoveClass(x[i], "show");
    if (x[i].className.indexOf(c) > -1) w3AddClass(x[i], "show");
  }
}

function w3AddClass(element, name) {
  var i, arr1, arr2;
  arr1 = element.className.split(" ");
  arr2 = name.split(" ");
  for (i = 0; i < arr2.length; i++) {
    if (arr1.indexOf(arr2[i]) == -1) {
      element.className += " " + arr2[i];
    }
  }
}

function w3RemoveClass(element, name) {
  var i, arr1, arr2;
  arr1 = element.className.split(" ");
  arr2 = name.split(" ");
  for (i = 0; i < arr2.length; i++) {
    while (arr1.indexOf(arr2[i]) > -1) {
      arr1.splice(arr1.indexOf(arr2[i]), 1);
    }
  }
  element.className = arr1.join(" ");
}

document.addEventListener("DOMContentLoaded", function() {
  // Add active class to the current button (highlight it)
  var btnContainer = document.getElementById("myBtnContainer");
  var btns = btnContainer.getElementsByClassName("btn");
  for (var i = 0; i < btns.length; i++) {
    btns[i].addEventListener("click", function() {
      var current = document.getElementsByClassName("active");
      current[0].className = current[0].className.replace(" active", "");
      this.className += " active";
    });
  }

  filterSelection("all");

});
<div id="myBtnContainer">
  <button class="btn mybtn active" onclick="filterSelection('all')"> Show all</button>
  <button class="btn mybtn" onclick="filterSelection('lower-body')"> Lower Body</button>
  <button class="btn mybtn" onclick="filterSelection('upper-body')"> Upper Body</button>
  <button class="btn mybtn" onclick="filterSelection('core')"> Core</button>
  <button class="btn mybtn" onclick="filterSelection('stretch')"> Stretch</button>
</div>

<!-- Portfolio Gallery Grid -->      
  <div class="row">       
      
    <div class="col-sm-6 col-md-4 column lower-body upper-body">
        <div class="content">
          <a href="" data-toggle="modal" data-target="#modalYT1 ">
            <img  src="https://via.placeholder.com/350x150?text=SingleBarPull-up " alt="Single Bar Pull-up" style="width:100%">
          </a>
          <h4>Single Bar Pull-up</h4>            
        </div>
    </div>  
   
    <div class="col-sm-6 col-md-4 column upper-body stretch">
        <div class="content">
          <a href="" data-toggle="modal" data-target="#modalYT2">
            <img  src="https://via.placeholder.com/350x150?text=Adducters" alt="Adducters" style="width:100%">
          </a>
          <h4>Adducters</h4>            
        </div>
    </div>  
    <div class="col-sm-6 col-md-4 column upper-body core">
          <div class="content">
            <a href="" data-toggle="modal" data-target="#modalYT3">
              <img  src="https://via.placeholder.com/350x150?text=KneeUps" alt="Knee Ups" style="width:100%">
            </a>
              <h4>Knee Ups</h4>            
          </div>
      </div> 
      <div class="col-sm-6 col-md-4 column core lower-body">
          <div class="content">
            <a href="" data-toggle="modal" data-target="#modalYT4">
              <img  src="https://via.placeholder.com/350x150?text=InclinePush-up" alt="Incline Push-up" style="width:100%">
            </a>
            <h4>Incline Push-up</h4>            
            </div>
        </div>          
    
  <!-- END ROW -->
  </div>
vermit25
  • 13
  • 5

1 Answers1

1

If you make your filter controls radio buttons instead of buttons, you can construct a CSS selector that targets the filtered items. Bootstrap can change the appearance of the radio buttons, but you'll need to include jQuery to get functionality.

function filterSelection() {
  // Get an array of checked filter radio buttons,
  const filteredClasses = $('#filters :checked').get()
  // convert it to an array of CSS classes,
    .map(el => '.' + el.value)
  // remove the "show all" filters,
    .filter(cls => cls !== '.all')
  // and join them all together into a single CSS selector
    .join('');

  // Hide all the .columns, then show the ones matching the filter
  $('.column').hide();
  $('.column' + filteredClasses).show();
}

document.addEventListener('DOMContentLoaded', () => {
  // Change events from all the radio buttons will bubble up to #filters
  // Bootstrap swallows the standard DOM event, so this has to use jQuery
  $('#filters').change(filterSelection);
});
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.bundle.min.js" integrity="sha384-xrRywqdh3PHs8keKZN+8zzc5TX0GRTLCcmivcbNJWm2rs5C8PRhcEn3czEjhAO9o" crossorigin="anonymous"></script>

<div id="filters">
  <div class="btn-group btn-group-toggle" data-toggle="buttons">
    <label class="btn btn-secondary active">
      <input type="radio" name="difficulty" value="all" checked>
      Show all
    </label>
    <label class="btn btn-secondary">
      <input type="radio" name="difficulty" value="beginner">
      Beginner
    </label>
    <label class="btn btn-secondary">
      <input type="radio" name="difficulty" value="mid">
      Mid
    </label>
    <label class="btn btn-secondary">
      <input type="radio" name="difficulty" value="advanced">
      Advanced
    </label>
  </div>
  <div class="btn-group btn-group-toggle" data-toggle="buttons">
    <label class="btn btn-secondary active">
      <input type="radio" name="target" value="all" checked>
      Show all
    </label>
    <label class="btn btn-secondary">
      <input type="radio" name="target" value="lower-body">
      Lower Body
    </label>
    <label class="btn btn-secondary">
      <input type="radio" name="target" value="upper-body">
      Upper Body
    </label>
    <label class="btn btn-secondary">
      <input type="radio" name="target" value="core">
      Core
    </label>
    <label class="btn btn-secondary">
      <input type="radio" name="target" value="stretch">
      Stretch
    </label>
  </div>
</div>

<!-- Portfolio Gallery Grid -->
<div class="row">

  <div class="col-sm-6 col-md-4 column lower-body upper-body beginner">
    <div class="content">
      <a href="" data-toggle="modal" data-target="#modalYT1 ">
        <img src="https://via.placeholder.com/350x150?text=SingleBarPull-up " alt="Single Bar Pull-up" style="width:100%">
      </a>
      <h4>Single Bar Pull-up</h4>
    </div>
  </div>

  <div class="col-sm-6 col-md-4 column upper-body stretch mid">
    <div class="content">
      <a href="" data-toggle="modal" data-target="#modalYT2">
        <img src="https://via.placeholder.com/350x150?text=Adducters" alt="Adducters" style="width:100%">
      </a>
      <h4>Adducters</h4>
    </div>
  </div>
  <div class="col-sm-6 col-md-4 column upper-body core mid">
    <div class="content">
      <a href="" data-toggle="modal" data-target="#modalYT3">
        <img src="https://via.placeholder.com/350x150?text=KneeUps" alt="Knee Ups" style="width:100%">
      </a>
      <h4>Knee Ups</h4>
    </div>
  </div>
  <div class="col-sm-6 col-md-4 column core lower-body advanced">
    <div class="content">
      <a href="" data-toggle="modal" data-target="#modalYT4">
        <img src="https://via.placeholder.com/350x150?text=InclinePush-up" alt="Incline Push-up" style="width:100%">
      </a>
      <h4>Incline Push-up</h4>
    </div>
  </div>

  <!-- END ROW -->
</div>

You can do the same thing without Bootstrap or jQuery, using some CSS to style the radio buttons:

function filterSelection() {
  // Create the CSS selector
  const filteredClasses = [...document.querySelectorAll('#filters :checked')]
    .map(el => '.' + el.value)
    .filter(cls => cls !== '.all')
    .join('');

  // Hide or show each item in one pass
  document.querySelectorAll('.column').forEach(el => {
    // .matches() chokes on '', so use '*' in that case
    el.style.display = el.matches(filteredClasses || '*') ? '' : 'none';
  });
}

document.addEventListener('DOMContentLoaded', () => {
  document.querySelector('#filters').addEventListener('change', filterSelection);
});
#filters input {
  display: none;
}

#filters label {
  display: inline-block;
  padding: 0.25em 1em;
  border: 2px solid transparent;
}

#filters :checked + label {
  border: 2px solid blue;
}
<div id="filters">
  <div>
    <input type="radio" name="difficulty" value="all" id="difficulty-all" checked>
    <label for="difficulty-all">Show all</label>
    <input type="radio" name="difficulty" value="beginner" id="difficulty-beginner">
    <label for="difficulty-beginner">Beginner</label>
    <input type="radio" name="difficulty" value="mid" id="difficulty-mid">
    <label for="difficulty-mid">Mid</label>
    <input type="radio" name="difficulty" value="advanced" id="difficulty-advanced">
    <label for="difficulty-advanced">Advanced</label>
  </div>
  <div>
    <input type="radio" name="target" value="all" id="target-all" checked>
    <label for="target-all">Show all</label>
    <input type="radio" name="target" value="lower-body" id="target-lower-body">
    <label for="target-lower-body">Lower Body</label>
    <input type="radio" name="target" value="upper-body" id="target-upper-body">
    <label for="target-upper-body">Upper Body</label>
    <input type="radio" name="target" value="core" id="target-core">
    <label for="target-core">Core</label>
    <input type="radio" name="target" value="stretch" id="target-stretch">
    <label for="target-stretch">Stretch</label>
  </div>
</div>

<!-- Portfolio Gallery Grid -->
<div class="row">

  <div class="col-sm-6 col-md-4 column lower-body upper-body beginner">
    <div class="content">
      <a href="" data-toggle="modal" data-target="#modalYT1 ">
        <img src="https://via.placeholder.com/350x150?text=SingleBarPull-up " alt="Single Bar Pull-up" style="width:100%">
      </a>
      <h4>Single Bar Pull-up</h4>
    </div>
  </div>

  <div class="col-sm-6 col-md-4 column upper-body stretch mid">
    <div class="content">
      <a href="" data-toggle="modal" data-target="#modalYT2">
        <img src="https://via.placeholder.com/350x150?text=Adducters" alt="Adducters" style="width:100%">
      </a>
      <h4>Adducters</h4>
    </div>
  </div>
  <div class="col-sm-6 col-md-4 column upper-body core mid">
    <div class="content">
      <a href="" data-toggle="modal" data-target="#modalYT3">
        <img src="https://via.placeholder.com/350x150?text=KneeUps" alt="Knee Ups" style="width:100%">
      </a>
      <h4>Knee Ups</h4>
    </div>
  </div>
  <div class="col-sm-6 col-md-4 column core lower-body advanced">
    <div class="content">
      <a href="" data-toggle="modal" data-target="#modalYT4">
        <img src="https://via.placeholder.com/350x150?text=InclinePush-up" alt="Incline Push-up" style="width:100%">
      </a>
      <h4>Incline Push-up</h4>
    </div>
  </div>

  <!-- END ROW -->
</div>
AuxTaco
  • 4,883
  • 1
  • 12
  • 27
  • Wow thanks so much and sorry for not replying sooner. Will implement this shortly. Really appreciate you taking the time to do this for me. – vermit25 Aug 29 '19 at 15:48
  • Would it be possible to have the buttons as dropdowns? – vermit25 Aug 29 '19 at 17:38
  • @vermit25 Yes, just use ` – AuxTaco Aug 30 '19 at 00:19
  • Thanks again, I wont be able to test this out right away as I have been assigned on a different project, but will try that soon. – vermit25 Aug 30 '19 at 13:29