У меня есть две области типов контента, которые содержат уникальные параметры фильтра. Это:
typetagЯ пытаюсь использовать isotope.js, чтобы добиться макета двойной фильтрации, но он всегда отдает приоритет фильтру, на который нажали последним.
См. пример использования здесь (ссылка ниже демо):
Комбинированные фильтры не работают.
В документации говорится, что метод arrange() может обрабатывать несколько экземпляров фильтра, но в моем случае он не работает.
Я также пробовал использовать функцию concatValues() для объединения значений (как показано во многих демонстрациях), но она все равно не дает правильных результатов.
Интерактивную демонстрацию смотрите здесь.
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.info('List Item:', listItem);
console.info('Filter Group:', filterGroup);
console.info('Filter Value:', filterValue);
console.info('Filters Object:', filters);
console.info('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>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.info('List Item:', listItem);
// console.info('Filter Group:', filterGroup);
// console.info('Filter Value:', filterValue);
// console.info('Filters Object:', filters);
// console.info('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);
});
});
});


![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Вам необходимо обновить значение объекта, которое создается при каждом щелчке по тегу/типу с выбранным значением, а затем использовать этот обновленный массив для передачи в фильтр.
В приведенном ниже коде я добавил условие, т.е.: если в целевом элементе есть выбранный класс, тогда только добавьте/обновите значение массива (фильтров), иначе просто удалите это значение фильтра данных из ключа.
Демо-код:
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.info(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/[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 = ".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>Посмотрите видео-демонстрацию моего сообщения выше: i.imgur.com/MtBWXcB.mp4
Привет, я в замешательстве, потому что в заданном тобой вопросе ты сказал If I then also click "PDF", I should then see no posts (as no blog post that has pdf as a class exists).. что тогда это значит?
Извиняюсь, Свати, кажется, я сам запутался во время написания вопроса и заметил неправильный вариант использования. Чтобы уточнить, фильтры по своей природе являются «флажками», и все, что есть .selected, должно отображаться в результатах. Т.е. если проверяются блоги и тематические исследования, то должны отображаться оба из них (а не результаты, которым присвоены оба .blogs-and-news.case-studies. Имеет ли это смысл?
Да, @Фредди. Пожалуйста, проверьте, работает ли обновленный ответ для вас.
Привет, Свати, то, что ты сделал, — это именно то, что мне нужно в описанном выше варианте использования. Хотя требование/логика изменилась с момента вашего ответа. Поскольку вы ответили на исходный вопрос, я отмечу это как ответ (спасибо за помощь). Но мне также интересно, можете ли вы помочь мне с измененным вариантом использования, который я подробно описал в новом вопросе здесь: stackoverflow.com/questions/77217964/…
Привет, Свати, спасибо за твой ответ. Однако похоже, что ваша демо-версия демонстрирует результаты, которые точно соответствуют результатам
filterValue. Например, посмотрите этот JSFiddle на основе вашей демонстрации: jsfiddle.net/7f6ujL9t. В этом фрагменте, если вы выберете следующие параметры «блоги и новости», «статья» и «pdf». Это не дает никаких результатов, на самом деле должно отображаться сообщение «Блоги и новости, статьи, тематическое исследование», потому что оно имеет 2 фильтра («блог и новости» и «статья»).