I'm using Isotope.js for filtering which includes buttons and a search bar. I know combination filters can work in Isotope because this Codepen showcases a working demo of it.
However, adapting the above to my use case doesn't seem to work.
See my demo here:
document.addEventListener('DOMContentLoaded', function() {
// store filter for each group
var buttonFilters = {};
var buttonFilter;
// quick search regex
var qsRegex;
var container = document.querySelector('.grid');
var gridItems = container.querySelectorAll('.grid-item');
var searchInput = document.querySelector('.rSidebar__search');
var resourceCards = document.querySelectorAll(".resourceCard");
/*
* init Isotope
*/
var iso = new Isotope(container, {
itemSelector: '.resourceCard',
layoutMode: 'fitRows',
transitionDuration: '0.5s',
// filter: function( itemElem ) {
// return qsRegex ? itemElem.textContent.match( qsRegex ) : true;
// },
filter: function (itemElem) {
var item = this;
var $item = item;
var textContent = $item.textContent;
// Check if textContent is defined before calling match
var searchResult = qsRegex ? itemElem.textContent.match( qsRegex ) : true;
var buttonResult = buttonFilter ? $item.is(buttonFilter) : true;
return searchResult && buttonResult;
},
});
/*
* search filtering
*/
// use value of search field to filter
searchInput.addEventListener('keyup', debounce(function () {
qsRegex = new RegExp(searchInput.value, 'gi');
iso.arrange();
}, 200));
// flatten object by concatting values
function concatValues( obj ) {
var value = '';
for ( var prop in obj ) {
value += obj[ prop ];
}
return value;
}
// debounce so filtering doesn't happen every millisecond
function debounce( fn, threshold ) {
var timeout;
threshold = threshold || 100;
return function debounced() {
clearTimeout( timeout );
var args = arguments;
var _this = this;
function delayed() {
fn.apply( _this, args );
}
timeout = setTimeout( delayed, threshold );
};
}
/*
* Create functions to sort isotope cards
*/
function sortCards(){
var selectedFilters = [];
document.querySelectorAll('.selected').forEach(function(selectedItem) {
selectedFilters.push(selectedItem.getAttribute('data-filter'));
});
var selector = selectedFilters.join(', ');
iso.arrange({ filter: selector });
}
/*
* Perform isotope filtering on li click
*/
const optionLinks = document.querySelectorAll('.rSidebar__options-li');
optionLinks.forEach(function(optionLink) {
optionLink.addEventListener('click', function(event) {
event.preventDefault();
console.log(event);
this.classList.toggle('selected');
sortCards();
// Scroll to the top of the #all-posts element smoothly
const allPostsElement = document.getElementById('all-posts');
if (allPostsElement) {
allPostsElement.scrollIntoView({ behavior: 'smooth' });
}
});
});
iso.layout();
/* another test */
// var optionLinks2 = document.querySelectorAll('.rSidebar__options-li');
//
// // Add a click event listener to the 'filters' element
// optionLinks2.forEach(function(optionLink2) {
// optionLink2.addEventListener('click', function(event) {
//
//
// var target = event.target;
//
// console.log(target);
//
// // Check if the clicked element has the class 'button'
// if (target.classList.contains('buttonTemp')) {
// var buttonGroup = target.closest('.button-group');
// console.log("buttonGroup " + buttonGroup);
// var filterGroup = buttonGroup.getAttribute('data-filter-group');
// console.log("filterGroup " + filterGroup);
// var dataFilter = target.getAttribute('data-filter');
// console.log("dataFilter " + dataFilter);
//
// // Set filter for the group
// buttonFilters[filterGroup] = dataFilter;
//
// // Combine filters
// var buttonFilter = concatValues(buttonFilters);
//
// // Isotope arrange
// iso.layout();
//
//
//
// }
// });
// });
/*
* end
*/
});
.container {
padding: 100px 0;
}
.rSidebar__options {
padding-left: 0;
}
.rSidebar__options-li {
margin-bottom: 17px;
display: flex;
align-items: center;
cursor: pointer;
width: -webkit-fit-content;
width: -moz-fit-content;
width: fit-content;
}
.rSidebar__options-li.selected .rSidebar__options-square {
background-color: blue;
}
.rSidebar__options-square {
height: 20px;
width: 20px;
border: 2px solid black;
}
.rSidebar__options-label {
margin-left: 10px;
}
.resourceCard {
border: 2px solid black;
}
<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="container">
<div class="row justify-content-between">
<div class="col-3">
<div class="rSidebar">
<input class="rSidebar__search" type="text" placeholder="Search" name="search" aria-label="Search">
<ul class="rSidebar__options button-group" data-filter-group="type">
<li class="rSidebar__options-li" data-filter=".blogs-and-news" data-query="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" data-query="case-studies">
<span class="rSidebar__options-square"></span>
<span class="rSidebar__options-label d-block buttonTemp" data-filter=".case-study">Case Studies</span>
</li>
</ul>
</div>
</div>
<div class="col-7">
<div class="grid">
<article class="resourceCard grid-item case-study">
<div class="resourceCard__body background--white d-flex flex-column">
<span class="resourceCard__body-title fw-bold" role="heading">Case study post</span>
</div>
</article>
<article class="resourceCard grid-item blogs-and-news">
<div class="resourceCard__body background--white d-flex flex-column">
<span class="resourceCard__body-title fw-bold" role="heading">Blogs and news post</span>
</div>
</article>
</div>
</div>
</div>
</div>
In the above, perform the following steps to recreate the issue(s):
- When running the demo, search for "news" and it will filter to the news post (working)
- Rerun the demo and now click either of the checkbox options. This will sort the cards accordingly (working).
- Rerun the demo and now, enable both checkboxes, and then search for "news". This will not filter the cards (not working), to show the news post.
- Similar to the above, when a checkbox is enabled, and you search for a term that isn't present (e.g. "test"), it doesn't hide all the cards (to imply that no results found with that searched term).
I'm stumped with this one as I've tried to follow the demo and alter my code, but cannot see where my issue lies?