2

I want to add recursive filters using simple HTML buttons/javascript. Till now, i have only been able to add one level of filter. What i want to do is - allow the user to select the filter in 2 stages. For example, user should be able to filter on experience range "10+" and then further filter on next stage such as "Operations". So this way only profiles that fit 10+ experience and Operations are shown.

I have been able to add filter and logic for one stage. That is, the code works and filters on experience range (5-8, 8-10, 10+), but unable to implement the second stage of filter (IT, Operations etc.)

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(" ");
}


// 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";
  });
}
* {
  box-sizing: border-box;
}

body {
  background-color: #f1f1f1;
  padding: 20px;
  font-family: Arial;
}


/* Center website */

.main {
  max-width: 1000px;
  margin: auto;
}

h1 {
  font-size: 50px;
  word-break: break-all;
}

.row {
  margin: 8px -16px;
}


/* Add padding BETWEEN each column */

.row,
.row>.column {
  padding: 8px;
}


/* Create four equal columns that floats next to each other */

.column {
  float: left;
  width: 25%;
  display: none;
  /* Hide all elements by default */
}


/* Clear floats after rows */

.row:after {
  content: "";
  display: table;
  clear: both;
}


/* Content */

.content {
  background-color: white;
  padding: 10px;
}


/* The "show" class is added to the filtered elements */

.show {
  display: block;
}


/* Style the buttons */

.btn {
  border: none;
  outline: none;
  padding: 12px 16px;
  background-color: white;
  cursor: pointer;
}

.btn:hover {
  background-color: #ddd;
}

.btn.active {
  background-color: #666;
  color: white;
}


/* Responsive layout - makes a two column-layout instead of four columns */

@media screen and (max-width: 900px) {
  .column {
    width: 50%;
  }
}


/* Responsive layout - makes the two columns stack on top of each other instead of next to each other */

@media screen and (max-width: 600px) {
  .column {
    width: 100%;
  }
}
<!-- MAIN (Center website) -->
<div class="main">

  <div id="myBtnContainer">
    <button class="btn active" onclick="filterSelection('all')"> Show all</button>
    <button class="btn" onclick="filterSelection('5-8')"> 5-8</button>
    <button class="btn" onclick="filterSelection('8-10')"> 8-10</button>
    <button class="btn" onclick="filterSelection('10+')"> 10+</button>
  </div>


  <div id="myBtnContainer">
    <button class="btn" onclick="filterSelection('Operations')"> Operations</button>
    <button class="btn" onclick="filterSelection('Manufacturing')"> Manufacturing</button>
  </div>

  <!-- Portfolio Gallery Grid -->
  <div class="row">
    <div class="column 8-10">
      <div class="content">
        <a href="https://xxx" target="_blank">
          <img src="https:xxx" alt="Bagish" style="width:100%" ;height:auto;>
          <h4>abc</h4>
          <p>8+ Experience in Oil&Gas, Manufacturing</p>
      </div>
    </div>
    <div class="column 10+">
      <div class="content">
        <a href="https://xxx">
          <img src="xxx" alt="def" style="width:100%" ;height:auto;>
          <h4>def</h4>
          <p>10+ Experience in Oil&Gas, Manufacturing</p>
      </div>
    </div>
    <div class="column 10+">
      <div class="content">
        <a href="https://abc">
          <img src="abc" ;height:auto;>
          <h4>ghi</h4>
          <p>13+ Experience in IT Program Management</p>
      </div>
    </div>
    <!-- END GRID -->
  </div>

  <!-- END MAIN -->
</div>

Please help me add another level of filter for IT/Operations etc.

3
  • Please form a minimal reproducible example, this is far more code than is necessary to illustrate what you're trying to do. Commented Aug 12, 2019 at 19:42
  • Your class names don't seem to include 'Manufacturing' or 'Operations'. How would those filters work? Commented Aug 12, 2019 at 19:45
  • I am not sure how to add additional filter logic for operations or manufacturing, since I want to add that filter on top of the existing filter. Please help. Commented Aug 12, 2019 at 19:59

1 Answer 1

1

A bit adjusted and simplified, but suppose works as you wanted ;-)
In case you are happy, mind pressing accept button (under voting).

var filtersList = {};

filterSelection(document.getElementsByName("myBtnContainer")[0].children[0]);

function renameAll(i) {
  return i.replace('Show all', 'all');
}
function filterSelection(current) {
  var x, i;
  var c = renameAll(current.innerText.trim());
  var buttons = document.getElementsByName("myBtnContainer");
  var group = current;
  do {
    group = group.parentElement;
    if (group.getAttribute("name") == "myBtnContainer") {
      for (i = 0;i<buttons.length;i++) {
        if (buttons[i] === group) {
          group = i + 1;
          break;
        }
      }
      break;
    }
  } while (true);
  var has = filtersList[c];
  if (!has) {
    if (filtersList.all && group == 1) filtersList = {};
    if (c == 'all') filtersList = { all:1 }
    else filtersList[c] = group;
  } else {
    delete filtersList[c];
    if (c == 'all') filtersList = {};
  }
  var records = document.getElementsByClassName("column");
  var matched = 0, filtersNo = [null,null];
  updateButtons(buttons, filtersNo);
  for (i = 0; i < records.length; i++) {
    w3RemoveClass(records[i], "show");
    var matchedFilters = [0,0];
    for(var c1 in filtersList) {
      var group = filtersList[c1]-1;
      if (c1 == "all") c1 = "";
      if (records[i].className.indexOf(c1) > -1) {
        matchedFilters[group]++;
  }
    }
    // Display trick here 2 binary numbers or logic table - each bit means non-zero number in group (matched > 0 / selected filter > 0) - hope works properly ;-)
    var matched = (!!matchedFilters[0]) + (!!matchedFilters[1])*2;
    var filters = (!!filtersNo[0]) + (!!filtersNo[1])*2;
    if ((matched & filters) == filters && (filters != 0)) {
          w3AddClass(records[i], "show");
    }
  }
  updateButtons(buttons, filtersNo);
}

function updateButtons(buttons, filtersNo) {
  filtersNo[0] = 0;
  filtersNo[1] = 0;
  for (i = 0;i<buttons.length;i++) {
    if (i && !filtersNo[0]) filtersList = {};
    for (var j = 0;j<buttons[i].children.length;j++) {
      var el = buttons[i].children[j];
      c = renameAll(el.innerHTML.trim());
      if (filtersList[c]) {
        filtersNo[i]++;
        if (el.className.indexOf("active") < 0) el.className += " active";
      } else {
        el.className = el.className.replace(/[ ]*active[ ]*/,'');
      }
    }
  }
  if (filtersNo[0]) {
    buttons[1].style.display = "";
  } else {
    buttons[1].style.display = "none";
  }
}

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(" ");
}
* {
  box-sizing: border-box;
}

body {
  background-color: #f1f1f1;
  padding: 20px;
  font-family: Arial;
}


/* Center website */

.main {
  max-width: 1000px;
  margin: auto;
}

h1 {
  font-size: 50px;
  word-break: break-all;
}

.row {
  margin: 8px -16px;
}


/* Add padding BETWEEN each column */

.row,
.row>.column {
  padding: 8px;
}


/* Create four equal columns that floats next to each other */

.column {
  float: left;
  width: 25%;
  display: none;
  /* Hide all elements by default */
}


/* Clear floats after rows */

.row:after {
  content: "";
  display: table;
  clear: both;
}


/* Content */

.content {
  background-color: white;
  padding: 10px;
}


/* The "show" class is added to the filtered elements */

.show {
  display: block;
}


/* Style the buttons */

.btn {
  border: none;
  outline: none;
  padding: 12px 16px;
  background-color: white;
  cursor: pointer;
}

.btn:hover {
  background-color: #ddd;
}

.btn.active {
  background-color: #666;
  color: white;
}


/* Responsive layout - makes a two column-layout instead of four columns */

@media screen and (max-width: 900px) {
  .column {
    width: 50%;
  }
}


/* Responsive layout - makes the two columns stack on top of each other instead of next to each other */

@media screen and (max-width: 600px) {
  .column {
    width: 100%;
  }
}
<div class="main">

  <div name="myBtnContainer">
    <button class="btn" onclick="filterSelection(this)"> Show all</button>
    <button class="btn" onclick="filterSelection(this)"> 5-8</button>
    <button class="btn" onclick="filterSelection(this)"> 8-10</button>
    <button class="btn" onclick="filterSelection(this)"> 10+</button>
  </div>


  <div name="myBtnContainer" style="display: none">
    <button class="btn" onclick="filterSelection(this)"> Operations</button>
    <button class="btn" onclick="filterSelection(this)"> Manufacturing</button>
  </div>

  <!-- Portfolio Gallery Grid -->
  <div class="row">
    <div class="column 8-10 Operations">
      <div class="content">
        <a href="https://mbaex2020.co/batchprofiledetails#7839de77-db6d-4c0e-9072-d60fb35d09c9" target="_blank">
          <img src="https://img1.wsimg.com/isteam/ip/97d4b213-5779-4c13-95cf-100a6b778fe3/Bagish.jpg/:/rs=w:600,h:750,cg:true,m/cr=w:1200,h:750,a:cc" alt="Bagish" style="width:100%" ;height:auto;>
          <h4>Bagish</h4>
          <p>8+ Experience in Oil&Gas, Manufacturing</p>
      </div>
    </div>
    <div class="column 10+ Operations">
      <div class="content">
        <a href="https://mbaex2020.co/batchprofiledetails#c55a69ed-2170-41cf-b71d-e6546bb77c14" target="_blank">
          <img src="https://img1.wsimg.com/isteam/ip/97d4b213-5779-4c13-95cf-100a6b778fe3/Rahul.jpg/:/rs=w:600,h:750,cg:true,m/cr=w:1200,h:750,a:cc" alt="Rahul" style="width:100%" ;height:auto;>
          <h4>Rahul</h4>
          <p>10+ Experience in Oil&Gas, Manufacturing</p>
      </div>
    </div>
    <div class="column 10+">
      <div class="content">
        <a href="https://mbaex2020.co/batchprofiledetails#c26922ff-3ee8-4d1e-92bf-974f46061d40" target="_blank">
          <img src="https://img1.wsimg.com/isteam/ip/97d4b213-5779-4c13-95cf-100a6b778fe3/Nikhil.jpg/:/rs=w:600,h:750,cg:true,m/cr=w:1200,h:750,a:cc" alt="Nikhil" style="width:100%" ;height:auto;>
          <h4>Nikhil</h4>
          <p>13+ Experience in IT Program Management</p>
      </div>
    </div>
    <!-- END GRID -->
  </div>

  <!-- END MAIN -->
</div>

Sign up to request clarification or add additional context in comments.

7 Comments

Thank you Tom for your response. I made the following change - <div class="column 8-10 Operations"> in the first div and <div class="column 10+ Operations"> in the third div, in the code you provided and tried testing it. I am unable to figure out why its not working as intended. Could you please help? I want to click on 8-10 button first and then click on Operations. Ideally only the first div should be shown, but what is happening is that it ignores the first filter (8-10) and on pressing the second button (Operations), its filtering all div's with Operations tag. Thanks so much!
Thank you. I need an AND logic for the 2 sets of buttons. I am not sure how to proceed. Any help is greatly appreciated. I need an AND logic between the 2 sets of buttons (5-8,8-10,10+ AND Operations, Manufacturing). I am trying to get the user to see div's that satisfy both these criteria. Thank you so much!
Thank you so much, now i understood how to write this piece. Appreciate your support. I have accepted this awesome answer! Thanks.
I have implemented this code on my test website, however, for some combination of filters, the code is not functioning correctly, I have tried various combinations but not able to fix. mbaex2020.co/student-profiles - when the user filter for experience range (9-11 AND 11+, you can see that the formatting is out of sorts). Could you help here?
CSS problem(?) or content - filter logic problem ?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.