Saturday, 30 September 2023

How do you combine multiple filters in isotope JS?

I have two content type areas which contain unique filter options. These are:

  1. type
  2. tag

I'm trying to utilise isotope.js, to achieve a dual filtering layout, but it always gives the last clicked filter priority.

See use case here (reference below demo):

  1. If I click "Blog & News", I should see two posts (works)
  2. If I then also click "PDF", I should then see no posts (as no blog post that has pdf as a class exists). Instead, it shows me the case study post that has the pdf class.
  3. If I then also click "article", it should again show me no posts as no post exists that has the class blog-and-news pdf article. But instead shows me the case study post with it.

The filters in combination isn't working.

The documentation says the arrange() method can handle multiple filter instances, but it isn't working in my use case.

I've also tried using the concatValues() function to concatenate the values (as shown in many demos), but it still doesn't yield the correct results.

See interactive demo here.

document.addEventListener('DOMContentLoaded', function() {

  var container = document.querySelector('.grid');
  var gridItems = container.querySelectorAll('.grid-item');
  const optionLinks = document.querySelectorAll('.rSidebar__options-li');

  var iso = new Isotope(container, {
    itemSelector: '.resourceCard',
    layoutMode: 'fitRows',
    transitionDuration: '0.5s',
  });

  var filters = {};

  function concatValues( obj ) {
    var value = '';
    for ( var prop in obj ) {
      value += obj[ prop ];
    }
    return value;
  }

  function handleFilterClick(event, filters, iso) {
    var listItem = event.target;
    var filterGroup = listItem.closest('.rSidebar__options').getAttribute('data-filter-group');
    var filterValue = listItem.getAttribute('data-filter');

    if (filters[filterGroup] === filterValue) {
      delete filters[filterGroup];
    } else {
      filters[filterGroup] = filterValue;
    }

    // Combine filters
    var filterValues = Object.values(filters).join(', ');
    // var filterValues = concatValues( filters );


    // debugging
    console.log('List Item:', listItem);
    console.log('Filter Group:', filterGroup);
    console.log('Filter Value:', filterValue);
    console.log('Filters Object:', filters);
    console.log('Filter Values:', filterValues);

    iso.arrange({ filter: filterValues });
  }

  optionLinks.forEach(function(optionLink) {
    optionLink.addEventListener('click', function(event) {
      event.preventDefault();
      this.classList.toggle('selected');
      handleFilterClick(event, filters, iso);
    });
  });


});
.post {
  padding: 100px;
}

.rSidebar__box {
  margin-bottom: 30px;
}
.rSidebar__options {
  padding-left: 0;
}
.rSidebar__options-li {
  margin-bottom: 17px;
  display: flex;
  align-items: center;
  cursor: pointer;
  width: fit-content;
}
.rSidebar__options-li.selected .rSidebar__options-square {
  background-color: #185A7D;
}
.rSidebar__options-square {
  height: 20px;
  width: 20px;
  transition: all 0.5s ease;
  border: 2px solid #000000;
}
.rSidebar__options-label {
  margin-left: 10px;
}

.grid {
  display: flex;
  flex-wrap: wrap;
  margin: -14px 0 0 -14px;
}
.grid-item {
  box-sizing: border-box;
  width: calc(33.33% - 14px);
  margin: 14px 0 18px 14px;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://unpkg.com/isotope-layout@3/dist/isotope.pkgd.min.js"></script>


<div class="post">
  <div class="container">
    <div class="row justify-content-between">

      <!-- SIDEBAR -->
      <div class="col-3">
        <div class="rSidebar">

          <!-- tags -->
          <div class="rSidebar__box">
            <span class="rSidebar__label d-block fw-bold">Filter by tag</span>
            <ul class="rSidebar__options button-group" data-filter-group="type">
              <li class="rSidebar__options-li" data-filter=".pdf">
                <span class="rSidebar__options-square"></span>
                <span class="rSidebar__options-label d-block buttonTemp" data-filter=".pdf">PDF</span>
              </li>
                <li class="rSidebar__options-li" data-filter=".article">
                <span class="rSidebar__options-square"></span>
                <span class="rSidebar__options-label d-block buttonTemp" data-filter=".article">Article</span>
              </li>
            </ul>
          </div>

          <!--  type -->
          <div class="rSidebar__box">
            <span class="rSidebar__label d-block fw-bold">Filter by type</span>
            <ul class="rSidebar__options button-group" data-filter-group="type">
              <li class="rSidebar__options-li" data-filter=".blogs-and-news">
                <span class="rSidebar__options-square"></span>
                <span class="rSidebar__options-label d-block buttonTemp" data-filter=".blogs-and-news">Blog & News</span>
              </li>
                <li class="rSidebar__options-li" data-filter=".case-study">
                <span class="rSidebar__options-square"></span>
                <span class="rSidebar__options-label d-block buttonTemp" data-filter=".case-study">Case Studies</span>
              </li>
            </ul>
          </div>
          <!-- end -->
        </div>
      </div>
      <!-- END -->

      <!-- GRID -->
      <div class="col-7">
        <div class="grid">
          <article class="resourceCard grid-item case-study pdf"><span class="resourceCard__body-title">Case study, PDF post</span></article>
          <article class="resourceCard grid-item blogs-and-news"><span class="resourceCard__body-title">Blogs and news post</span></article>
          <article class="resourceCard grid-item blogs-and-news article"><span class="resourceCard__body-title">Blogs and news, article post</span></article>
        </div>
      </div>
      <!-- END -->

    </div>
  </div>
</div>

Latest attempt

document.addEventListener('DOMContentLoaded', function() {

  var container = document.querySelector('.grid');
  var gridItems = container.querySelectorAll('.grid-item');
  const optionLinks = document.querySelectorAll('.rSidebar__options-li');

  var iso = new Isotope(container, {
    itemSelector: '.resourceCard',
    layoutMode: 'fitRows',
    transitionDuration: '0.5s',
  });

  var filters = {};

  function concatValues( obj ) {
    var value = '';
    for ( var prop in obj ) {
      value += obj[ prop ];
    }
    return value;
  }

  function handleFilterClick(event, filters, iso) {
    var listItem = event.target;
    var filterGroup = listItem.closest('.rSidebar__options').getAttribute('data-filter-group');
    var filterValue = listItem.getAttribute('data-filter');

    var allowMultiple = listItem.closest('.rSidebar__options').getAttribute('data-multiple') === 'true';

    if (allowMultiple) {
      // toggle the filter value
      if (filters[filterGroup] && filters[filterGroup].includes(filterValue)) {
        // remove the filter value if it already exists
        filters[filterGroup] = filters[filterGroup].filter(value => value !== filterValue);
      } else {
        // add the filter value if it doesn't exist
        if (!filters[filterGroup]) {
          filters[filterGroup] = [];
        }
        filters[filterGroup].push(filterValue);
      }
    } else {
      // replace the filter value
      filters[filterGroup] = [filterValue];
    }

    var filterValues = concatValues( filters );

    // console.log('List Item:', listItem);
    // console.log('Filter Group:', filterGroup);
    // console.log('Filter Value:', filterValue);
    // console.log('Filters Object:', filters);
    // console.log('Filter Values:', filterValues);

    iso.arrange({ filter: filterValues });

  }


  optionLinks.forEach(function(optionLink) {
    optionLink.addEventListener('click', function(event) {
      event.preventDefault();
      this.classList.toggle('selected');
      handleFilterClick(event, filters, iso);
    });
  });


});


from How do you combine multiple filters in isotope JS?

No comments:

Post a Comment