I have two content type areas which contain unique filter options. These are:
typetag
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):
- If I click "Blog & News", I should see two posts (works)
- If I then also click "Case studies", I should see both case studies and blog posts. Any item that is checked should show in the listing.
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/[email protected]/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);
});
});
});
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 :