Reputation: 1111
I've been trying integrate a filter functionality using a library called Isotope.js. Included with filter is a pagination functionality. I've been trying to solve the issue on how I can make the pagination work on multiple isotope
instances. It seems that pagination is duplicating itself multiple times when using the filter and affecting other instances present when using the pagination
Below is a sample work in progress of what I'm currently working on
var itemSelector = ".products-item";
var $checkboxes = $('.filter-checkbox');
var $container = $('.products-container').isotope({
itemSelector: itemSelector
});
//Ascending order
var responsiveIsotope = [
[480, 3],
[720, 5]
];
var itemsPerPageDefault = 5;
var itemsPerPage = defineItemsPerPage();
var currentNumberPages = 1;
var currentPage = 1;
var currentFilter = '*';
var filterAttribute = 'data-filter';
var filterValue = "";
var pageAttribute = 'data-page';
var pagerClass = 'isotope-pager';
// update items based on current filters
function changeFilter(selector) {
$container.isotope({
filter: selector
});
}
//grab all checked filters and goto page on fresh isotope output
function goToPage(n) {
currentPage = n;
var selector = itemSelector;
var exclusives = [];
// for each box checked, add its value and push to array
$checkboxes.each(function(i, elem) {
if (elem.checked) {
selector += (currentFilter != '*') ? '.' + elem.value : '';
exclusives.push(selector);
}
});
// smash all values back together for 'and' filtering
filterValue = exclusives.length ? exclusives.join('') : '*';
// add page number to the string of filters
var wordPage = currentPage.toString();
filterValue += ('.' + wordPage);
changeFilter(filterValue);
}
// determine page breaks based on window width and preset values
function defineItemsPerPage() {
var pages = itemsPerPageDefault;
for (var i = 0; i < responsiveIsotope.length; i++) {
if ($(window).width() <= responsiveIsotope[i][0]) {
pages = responsiveIsotope[i][1];
break;
}
}
return pages;
}
function setPagination() {
var SettingsPagesOnItems = function() {
var itemsLength = $container.children(itemSelector).length;
var pages = Math.ceil(itemsLength / itemsPerPage);
var item = 1;
var page = 1;
var selector = itemSelector;
var exclusives = [];
// for each box checked, add its value and push to array
$checkboxes.each(function(i, elem) {
if (elem.checked) {
selector += (currentFilter != '*') ? '.' + elem.value : '';
exclusives.push(selector);
}
});
// smash all values back together for 'and' filtering
filterValue = exclusives.length ? exclusives.join('') : '*';
// find each child element with current filter values
$container.children(filterValue).each(function() {
// increment page if a new one is needed
if (item > itemsPerPage) {
page++;
item = 1;
}
// add page number to element as a class
wordPage = page.toString();
var classes = $(this).attr('class').split(' ');
var lastClass = classes[classes.length - 1];
// last class shorter than 4 will be a page number, if so, grab and replace
if (lastClass.length < 4) {
$(this).removeClass();
classes.pop();
classes.push(wordPage);
classes = classes.join(' ');
$(this).addClass(classes);
} else {
// if there was no page number, add it
$(this).addClass(wordPage);
}
item++;
});
currentNumberPages = page;
}();
// create page number navigation
var CreatePagers = function() {
var $isotopePager = ($('.' + pagerClass).length == 0) ? $('<div class="' + pagerClass + '"></div>') : $('.' + pagerClass);
$isotopePager.html('');
if (currentNumberPages > 1) {
for (var i = 0; i < currentNumberPages; i++) {
var $pager = $('<a href="javascript:void(0);" class="pager" ' + pageAttribute + '="' + (i + 1) + '"></a>');
$pager.html(i + 1);
$pager.click(function() {
var page = $(this).eq(0).attr(pageAttribute);
goToPage(page);
});
$pager.appendTo($isotopePager);
}
}
$container.after($isotopePager);
}();
}
// remove checks from all boxes and refilter
function clearAll() {
$checkboxes.each(function(i, elem) {
if (elem.checked) {
elem.checked = null;
}
});
currentFilter = '*';
setPagination();
goToPage(1);
}
setPagination();
goToPage(1);
//event handlers
$checkboxes.change(function() {
var filter = $(this).attr(filterAttribute);
currentFilter = filter;
setPagination();
goToPage(1);
});
$('#clear-filters').click(function() {
clearAll()
});
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block;
}
body {
line-height: 1;
}
ol,
ul {
list-style: none;
}
blockquote,
q {
quotes: none;
}
blockquote:before,
blockquote:after,
q:before,
q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
.centered-component {
width: 100%;
max-width: 1300px;
margin: 0 auto;
display: flex;
flex-wrap: wrap;
padding: 100px 0;
}
.centered-component .filter-sidebar {
width: 100%;
max-width: 250px;
margin-right: 24px;
}
.centered-component .content-block {
flex: 1;
}
.filter-sidebar {
display: flex;
flex-direction: column;
}
.products-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 24px;
}
.isotope-container>h2 {
margin-bottom: 48px;
}
.products-item {
position: relative !important;
top: initial !important;
left: initial !important;
}
.products-container {
height: initial !important;
}
.isotope-pager {
margin-top: 42px;
}
.isotope-container+.isotope-container {
margin-top: 64px;
}
<!doctype html>
<html>
<head>
<title>Isotope</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="centered-component">
<div class="filter-sidebar">
<label class="filter-item">
<input type="checkbox" class="filter-checkbox" value="beige" />
beige
</label>
<label class="filter-item">
<input type="checkbox" class="filter-checkbox" value="green" />
green
</label>
<label class="filter-item">
<input type="checkbox" class="filter-checkbox" value="blue" />
blue
</label>
<label class="filter-item">
<input type="checkbox" class="filter-checkbox" value="orange" />
orange
</label>
<label class="filter-item">
<input type="checkbox" class="filter-checkbox" value="purple" />
purple
</label>
<label class="filter-item">
<input type="checkbox" class="filter-checkbox" value="pink" />
pink
</label>
<label class="filter-item">
<input type="checkbox" class="filter-checkbox" value="teal" />
teal
</label>
<label class="filter-item">
<input type="checkbox" class="filter-checkbox" value="yellow" />
yellow
</label>
<label class="filter-item">
<input type="checkbox" class="filter-checkbox" value="black" />
black
</label>
</div>
<div class="content-block">
<div class="isotope-container">
<h2 class="heading">Category 1</h2>
<ul class="products-container">
<li class="products-item beige">
<h2>beige</h2>
</li>
<li class="products-item green">
<h2>green</h2>
</li>
<li class="products-item blue">
<h2>blue</h2>
</li>
<li class="products-item orange">
<h2>orange</h2>
</li>
<li class="products-item purple">
<h2>purple</h2>
</li>
<li class="products-item pink">
<h2>pink</h2>
</li>
<li class="products-item teal">
<h2>teal</h2>
</li>
<li class="products-item yellow">
<h2>yellow</h2>
</li>
<li class="products-item black ">
<h2>black</h2>
</li>
<li class="products-item beige">
<h2>beige</h2>
</li>
</ul>
</div>
<div class="isotope-container">
<h2 class="heading">Category 1</h2>
<ul class="products-container">
<li class="products-item beige">
<h2>beige</h2>
</li>
<li class="products-item green">
<h2>green</h2>
</li>
<li class="products-item blue">
<h2>blue</h2>
</li>
<li class="products-item orange">
<h2>orange</h2>
</li>
<li class="products-item purple">
<h2>purple</h2>
</li>
<li class="products-item pink">
<h2>pink</h2>
</li>
<li class="products-item teal">
<h2>teal</h2>
</li>
<li class="products-item yellow">
<h2>yellow</h2>
</li>
<li class="products-item black ">
<h2>black</h2>
</li>
<li class="products-item beige">
<h2>beige</h2>
</li>
</ul>
</div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.isotope/2.2.2/isotope.pkgd.min.js"></script>
<script src="filter.js "></script>
</body>
</html>
Upvotes: 2
Views: 517
Reputation: 26075
It is not working because your code doesn't support multiple instances of pager. I have modified your code a bit to allow multiple pager instance.
This is something to start with and by no means is a clean solution, it needs clean up in quiet a few places, nevertheless it will give you an idea why your current code is not working.
var itemSelector = ".products-item";
var $checkboxes = $('.filter-checkbox');
var filterAttribute = 'data-filter';
class IsotopContainer {
constructor(container) {
this.container = $(container);
//Ascending order
this.responsiveIsotope = [
[480, 3],
[720, 5]
];
this.itemsPerPageDefault = 5;
this.itemsPerPage = this.defineItemsPerPage();
this.currentNumberPages = 1;
this.currentPage = 1;
this.currentFilter = '*';
this.filterValue = "";
this.pageAttribute = 'data-page';
this.pagerClass = 'isotope-pager';
this.isotope = this.container.isotope({
itemSelector: itemSelector
});
}
// update items based on current filters
changeFilter(selector) {
this.container.isotope({
filter: selector
});
}
//grab all checked filters and goto page on fresh isotope output
goToPage(n) {
this.currentPage = n;
var selector = itemSelector;
var exclusives = [];
// for each box checked, add its value and push to array
$checkboxes.each((i, elem) => {
if (elem.checked) {
selector += (this.currentFilter != '*') ? '.' + elem.value : '';
exclusives.push(selector);
}
});
// smash all values back together for 'and' filtering
this.filterValue = exclusives.length ? exclusives.join('') : '*';
// add page number to the string of filters
var wordPage = this.currentPage.toString();
this.filterValue += ('.' + wordPage);
this.changeFilter(this.filterValue);
}
// determine page breaks based on window width and preset values
defineItemsPerPage() {
var pages = this.itemsPerPageDefault;
for (var i = 0; i < this.responsiveIsotope.length; i++) {
if ($(window).width() <= this.responsiveIsotope[i][0]) {
pages = this.responsiveIsotope[i][1];
break;
}
}
return pages;
}
setPagination() {
var SettingsPagesOnItems = () => {
var itemsLength = this.container.children(itemSelector).length;
var pages = Math.ceil(itemsLength / this.itemsPerPage);
var item = 1;
var page = 1;
var selector = itemSelector;
var exclusives = [];
// for each box checked, add its value and push to array
$checkboxes.each((i, elem) => {
if (elem.checked) {
selector += (this.currentFilter != '*') ? '.' + elem.value : '';
exclusives.push(selector);
}
});
// smash all values back together for 'and' filtering
this.filterValue = exclusives.length ? exclusives.join('') : '*';
// find each child element with current filter values
this.container.children(this.filterValue).each((i, child) => {
// increment page if a new one is needed
if (item > this.itemsPerPage) {
page++;
item = 1;
}
// add page number to element as a class
var $child = $(child);
var wordPage = page.toString();
var classes = $child.attr('class').split(' ');
var lastClass = classes[classes.length - 1];
// last class shorter than 4 will be a page number, if so, grab and replace
if (lastClass.length < 4) {
$child.removeClass();
classes.pop();
classes.push(wordPage);
classes = classes.join(' ');
$child.addClass(classes);
} else {
// if there was no page number, add it
$child.addClass(wordPage);
}
item++;
});
this.currentNumberPages = page;
};
// create page number navigation
var CreatePagers = () => {
var existingPager = this.container.siblings('.' + this.pagerClass);
var $isotopePager = (existingPager.length == 0) ? $('<div class="' + this.pagerClass + '"></div>') : existingPager;
$isotopePager.html('');
if (this.currentNumberPages > 1) {
for (var i = 0; i < this.currentNumberPages; i++) {
var $pager = $('<a href="javascript:void(0);" class="pager" ' + this.pageAttribute + '="' + (i + 1) + '"></a>');
$pager.html(i + 1);
$pager.click(e => {
var page = $(e.target).attr(this.pageAttribute);
this.goToPage(page);
});
$pager.appendTo($isotopePager);
}
}
this.container.after($isotopePager);
};
SettingsPagesOnItems();
CreatePagers();
}
}
var containers = $.map($('.products-container'), c => new IsotopContainer(c));
// remove checks from all boxes and refilter
function clearAll() {
$checkboxes.each(function(i, elem) {
if (elem.checked) {
elem.checked = null;
}
});
containers.forEach(c => {
c.currentFilter = '*';
c.setPagination();
c.goToPage(1);
});
}
containers.forEach(c => {
c.setPagination();
c.goToPage(1);
});
//event handlers
$checkboxes.change(function() {
var filter = $(this).attr(filterAttribute);
containers.forEach(c => {
c.currentFilter = filter;
c.setPagination();
c.goToPage(1);
});
});
$('#clear-filters').click(function() {
clearAll()
});
/* http://meyerweb.com/eric/tools/css/reset/
v2.0 | 20110126
License: none (public domain)
*/
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block;
}
body {
line-height: 1;
}
ol,
ul {
list-style: none;
}
blockquote,
q {
quotes: none;
}
blockquote:before,
blockquote:after,
q:before,
q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
.centered-component {
width: 100%;
max-width: 1300px;
margin: 0 auto;
display: flex;
flex-wrap: wrap;
padding: 100px 0;
}
.centered-component .filter-sidebar {
width: 100%;
max-width: 250px;
margin-right: 24px;
}
.centered-component .content-block {
flex: 1;
}
.filter-sidebar {
display: flex;
flex-direction: column;
}
.products-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 24px;
}
.isotope-container>h2 {
margin-bottom: 48px;
}
.products-item {
position: relative !important;
top: initial !important;
left: initial !important;
}
.products-container {
height: initial !important;
}
.isotope-pager {
margin-top: 42px;
}
.isotope-container+.isotope-container {
margin-top: 64px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.isotope/2.2.2/isotope.pkgd.min.js"></script>
<div class="centered-component">
<div class="filter-sidebar">
<label class="filter-item">
<input type="checkbox" class="filter-checkbox" value="beige" />
beige
</label>
<label class="filter-item">
<input type="checkbox" class="filter-checkbox" value="green" />
green
</label>
<label class="filter-item">
<input type="checkbox" class="filter-checkbox" value="blue" />
blue
</label>
<label class="filter-item">
<input type="checkbox" class="filter-checkbox" value="orange" />
orange
</label>
<label class="filter-item">
<input type="checkbox" class="filter-checkbox" value="purple" />
purple
</label>
<label class="filter-item">
<input type="checkbox" class="filter-checkbox" value="pink" />
pink
</label>
<label class="filter-item">
<input type="checkbox" class="filter-checkbox" value="teal" />
teal
</label>
<label class="filter-item">
<input type="checkbox" class="filter-checkbox" value="yellow" />
yellow
</label>
<label class="filter-item">
<input type="checkbox" class="filter-checkbox" value="black" />
black
</label>
</div>
<div class="content-block">
<div class="isotope-container">
<h2 class="heading">Category 1</h2>
<ul class="products-container">
<li class="products-item beige">
<h2>beige</h2>
</li>
<li class="products-item green">
<h2>green</h2>
</li>
<li class="products-item blue">
<h2>blue</h2>
</li>
<li class="products-item orange">
<h2>orange</h2>
</li>
<li class="products-item purple">
<h2>purple</h2>
</li>
<li class="products-item pink">
<h2>pink</h2>
</li>
<li class="products-item teal">
<h2>teal</h2>
</li>
<li class="products-item yellow">
<h2>yellow</h2>
</li>
<li class="products-item black ">
<h2>black</h2>
</li>
<li class="products-item beige">
<h2>beige</h2>
</li>
</ul>
</div>
<div class="isotope-container">
<h2 class="heading">Category 1</h2>
<ul class="products-container">
<li class="products-item beige">
<h2>beige</h2>
</li>
<li class="products-item green">
<h2>green</h2>
</li>
<li class="products-item blue">
<h2>blue</h2>
</li>
<li class="products-item orange">
<h2>orange</h2>
</li>
<li class="products-item purple">
<h2>purple</h2>
</li>
<li class="products-item pink">
<h2>pink</h2>
</li>
<li class="products-item teal">
<h2>teal</h2>
</li>
<li class="products-item yellow">
<h2>yellow</h2>
</li>
<li class="products-item black ">
<h2>black</h2>
</li>
<li class="products-item beige">
<h2>beige</h2>
</li>
</ul>
</div>
</div>
</div>
Upvotes: 1