I have two content type areas which contain unique filter options. These are:
type
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):
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.
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>
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);
});
});
});
You need to update the object value which is created whenever the tag/type is clicked with value selected and then use that updated array to pass in filter.
In below code I have added condition i.e : if there is selected class on the target element then only add/update the value of array (filters) else just remove that data-filter value from the key.
Demo Code :
var filters = {};
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',
});
function concatValues(obj) {
var value = [];
for (var prop in obj) {
value.push(obj[prop]);
}
return value.flat().join(', ');
}
function handleFilterClick(event, filters) {
console.clear()
var listItem = event;
var filterGroup = listItem.closest('.rSidebar__options').getAttribute('data-filter-group');
var data_filter = listItem.getAttribute('data-filter');
//if selected class present do below :
if (listItem.classList.contains('selected')) {
if (!filters[filterGroup]) {
filters[filterGroup] = []
}
filters[filterGroup].push(data_filter)
} else {
filters[filterGroup] = filters[filterGroup].filter(data => data !== data_filter)
}
var filterValues = concatValues(filters);
console.log(filterValues)
iso.arrange({
filter: filterValues
});
}
optionLinks.forEach(function(optionLink) {
optionLink.addEventListener('click', function(event) {
event.preventDefault();
this.classList.toggle('selected');
handleFilterClick(this, filters);
});
});
.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(45% - 14px);
margin: 14px 0 18px 14px;
border: 2px solid;
padding: 20px;
}
<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="tag">
<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>
<article class="resourceCard grid-item blogs-and-news article pdf case-study"><span class="resourceCard__body-title">Blogs and news,article,pdf,case study </span></article>
</div>
</div>
<!-- END -->
</div>
</div>
</div>