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.
The way I want it to function is:
- If only one
tag
is selected, then show results with thattag
- If more than one
tag
is selected, then show results that have any of those tags (both do not need to exist together on a card) - If a
type
is selected, only show results that fall under thattype
- If one
type
is selected and onetag
, show results for posts where thetag
exists on the selectedtype
- If one
type
is selected and multipletags
, then show posts that fall under that type that have either of thosetags
. - If more than one
type
is selected and one or moretag
s, then show posts where thetag
s exist on either type
For example, using my demo below, here are some use cases:
- If I click on "Video Demos & Tours", I should see two video posts (card 1 and 3) – WORKS
- If I click on "Video Demos & Tours" and then "Ansible", I should see only see card 3 – DOESN’T WORK
- If I click on "Blog & News", I should see 3 cards (card 2, 4, 5) – WORKS
- If I click on "Blog & News" and then "Ansible", I should see cards 4 and 5
- If I click on "Blog & News", "Ansible" and then "Automation", I should see cards 2,4 and 5
However, in my current demo, though the console log seems to be on the right lines, it doesn’t perform the way I intent it to.
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.push(obj[prop]);
}
return value.flat().join(", ");
}
function handleFilterClick(event, filters) {
var listItem = event;
var filterGroup = listItem
.closest(".rSidebar__options")
.getAttribute("data-filter-group");
var data_filter = listItem.getAttribute("data-filter");
if (filterGroup === "type") {
filters[filterGroup] = [data_filter];
} else {
if (!filters[filterGroup]) {
filters[filterGroup] = [];
}
if (listItem.classList.contains("selected")) {
filters[filterGroup].push(data_filter);
} else {
filters[filterGroup] = filters[filterGroup].filter(
(tag) => tag !== data_filter
);
}
}
// Combine the type filter with the selected tag filters using an AND relationship
var filterValues = [];
// Handle type filter
if (filters["type"]) {
filterValues.push("." + filters["type"][0]);
}
// Handle tags filter if it's defined
if (filters["tag"]) {
var selectedType = filters["type"][0];
filters["tag"].forEach((tag) => {
filterValues.push("." + selectedType + "." + tag);
});
}
var finalFilter = filterValues.join(", ");
console.log(finalFilter);
iso.arrange({
filter: finalFilter
});
}
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 black;
padding: 20px;
}
<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="tag">
<li class="rSidebar__options-li" data-filter="ansible">
<span class="rSidebar__options-square"></span>
<span class="rSidebar__options-label d-block" data-filter="ansible">Ansible</span>
</li>
<li class="rSidebar__options-li" data-filter="automation">
<span class="rSidebar__options-square"></span>
<span class="rSidebar__options-label d-block" data-filter="automation">Automation</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" data-filter="blogs-and-news">Blog & News</span>
</li>
<li class="rSidebar__options-li" data-filter="video-demos-tour">
<span class="rSidebar__options-square"></span>
<span class="rSidebar__options-label d-block" data-filter="video-demos-tours">Video Demos & Tours</span>
</li>
</ul>
</div>
<!-- end -->
</div>
</div>
<!-- END -->
<!-- GRID -->
<div class="col-7">
<div class="grid">
<article class="resourceCard grid-item video-demos-tour automation"><span class="resourceCard__body-title">Card 1<br>Type: Video Demo & Tour<br>Tag: Automation</span></article>
<article class="resourceCard grid-item blogs-and-news"><span class="resourceCard__body-title">Card 2<br>Type: Blog & News<br>Tag: Automation</span></article>
<article class="resourceCard grid-item video-demos-tour automation ansible"><span class="resourceCard__body-title">Card 3<br>Type: Video Demo & Tour<br>Tags: Automation, Ansible</span></article>
<article class="resourceCard grid-item blogs-and-news ansible"><span class="resourceCard__body-title">Card 4<br>Type: Blog & News<br>Tag: Ansible</span></article>
<article class="resourceCard grid-item blogs-and-news ansible"><span class="resourceCard__body-title">Card 5<br>Type: Blog & News<br>Tags: Ansible, Automations</span></article>
</div>
</div>
<!-- END -->
</div>
</div>
</div>
2
Answers
If I understand correctly, you want to combine filters of the same group with OR and between groups with AND:
In selectors (as used by Isotope), that would be:
You can build this by going over each group, combining every element with the previously build selectors:
Some general hints and recommendations:
automation
class, not sure if that is intentionalfilter
object with empty arrays for all existing groups, it spares you figuring out if the group property already exists later onHave a look at the updated snippet:
Does that make sense, does it help?
The question is: Let S = (0,1) ∪ (1,2) ∪ (3,4) and T = {0,1,2,3}. Then which of the following statements is(are) true?
There are infinitely many functions from S to T.
There are infinitely many strictly increasing functions from S to T.
The number of continuous functions from S to T is at most 120.
Every continuous function from S to T is differentiable.
Let’s analyze each statement:
There are infinitely many functions from S to T: This statement is true. A function from S to T is a rule that assigns each element in S to an element in T. Since there are 4 elements in T and each element in S can be assigned to any element in T, there are infinitely many such rules or functions.
There are infinitely many strictly increasing functions from S to T: This statement is false. A strictly increasing function is one where if x1 < x2 then f(x1) < f(x2). Given the sets S and T, there are no strictly increasing functions because the set S has infinitely many elements while set T has only 4 elements.
The number of continuous functions from S to T is at most 120: This statement is false. A continuous function is one where small changes in the input result in small changes in the output. Given the sets S and T, there are no continuous functions because the set S is a subset of real numbers (which is uncountable) while set T has only 4 elements (which is countable).
Every continuous function from S to T is differentiable: This statement is false. Differentiability implies continuity but not vice versa. That means if a function is differentiable at a point then it must be continuous at that point but if a function is continuous at a point it need not be differentiable at that point. But as we established earlier, there are no continuous functions from S to T given the nature of sets S and T.
So, the only true statement among these options is “There are infinitely many functions from S to T”.